This patchset introduces initial concepts in CoreSight complex system configuration support.
Configurations consist of 2 elements:- 1) Features - programming combinations for devices, applied to a class of device on the system (all ETMv4), or individual devices. 2) Configurations - a set of programmed features used when the named configuration is selected.
Features and configurations are declared as a data table, a set of register, resource and parameter requirements. Features and configurations are loaded into the system by the virtual cs_syscfg device. This then matches features to any registered devices and loads the feature into them.
Individual device classes that support feature and configuration register with cs_syscfg.
Once loaded a configuration can be enabled for a specific trace run. Configurations are registered with the perf cs_etm event as entries in cs_etm/cs_config. These can be selected on the perf command line as follows:-
perf record -e cs_etm/<config_name>/ ...
This patch set has one pre-loaded configuration and feature. A named "strobing" feature is provided for ETMv4. A named "autofdo" configuration is provided. This configuration enables strobing on any ETM in used.
Thus the command: perf record -e cs_etm/autofdo/ ...
will trace the supplied application while enabling the "autofdo" configuation on each ETM as it is enabled by perf. This in turn will enable strobing for the ETM - with default parameters. Parameters can be adjusted using configfs.
The sink used in the trace run will be automatically selected.
A configuation can supply up to 15 of preset parameter values, which will subsitute in parameter values for any feature used in the configuration.
Selection of preset values as follows perf record -e cs_etm/autofdo,preset=1/ ...
(valid presets 1-N, where N is the number supplied in the configuration, not exceeding 15. preset=0 is the same as not selecting a preset.)
Applies to coresight/next (5.10-rc1 base)
Changes since v2: 1) Added documentation file. 2) Altered cs_syscfg driver to no longer be coresight_device based, and moved to its own custom bus to remove it from the main coresight bus. (Mathieu) 3) Added configfs support to inspect and control loaded configurations and features. Allows listing of preset values (Yabin Cui) 4) Dropped sysfs support for adjusting feature parameters on the per device basis, in favour of a single point adjustment in configfs that is pushed to all device instances. 5) Altered how the config and preset command line options are handled in perf and the drivers. (Mathieu and Suzuki). 6) Fixes for various issues and technical points (Mathieu, Yabin)
Changes since v1: 1) Moved preloaded configurations and features out of individual drivers. 2) Added cs_syscfg driver to manage configurations and features. Individual drivers register with cs_syscfg indicating support for config, and provide matching information that the system uses to load features into the drivers. This allows individual drivers to be updated on an as needed basis - and removes the need to consider devices that cannot benefit from configuration - static replicators, funnels, tpiu. 3) Added perf selection of configuarations. 4) Rebased onto the coresight module loading set.
To follow in future revisions / sets:- a) load of additional config and features by loadable module. b) load of additional config and features by configfs c) enhanced resource management for ETMv4 and checking features have sufficient resources to be enabled. d) ECT and CTI support for configuration and features.
Mike Leach (9): coresight: syscfg: Initial coresight system configuration coresight: syscfg: Add registration and feature loading for cs devices coresight: config: Add configuration and feature generic functions coresight: etm-perf: update to handle configuration selection coresight: etm4x: Add complex configuration handlers to etmv4 coresight: config: Add preloaded configurations coresight: syscfg: Add initial configfs support. coresight: syscfg: Allow update of feature params from configfs coresight: docs: Add documentation for CoreSight config.
.../trace/coresight/coresight-config.rst | 230 ++++++ Documentation/trace/coresight/coresight.rst | 16 + drivers/hwtracing/coresight/Makefile | 6 +- .../coresight/coresight-cfg-preload.c | 160 +++++ .../hwtracing/coresight/coresight-config.c | 392 +++++++++++ .../hwtracing/coresight/coresight-config.h | 311 +++++++++ drivers/hwtracing/coresight/coresight-core.c | 18 +- .../hwtracing/coresight/coresight-etm-perf.c | 166 ++++- .../hwtracing/coresight/coresight-etm-perf.h | 10 +- .../hwtracing/coresight/coresight-etm4x-cfg.c | 181 +++++ .../hwtracing/coresight/coresight-etm4x-cfg.h | 29 + .../coresight/coresight-etm4x-core.c | 36 +- .../coresight/coresight-etm4x-sysfs.c | 3 + .../coresight/coresight-syscfg-configfs.c | 421 +++++++++++ .../coresight/coresight-syscfg-configfs.h | 47 ++ .../hwtracing/coresight/coresight-syscfg.c | 656 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 83 +++ include/linux/coresight.h | 7 + 18 files changed, 2743 insertions(+), 29 deletions(-) create mode 100644 Documentation/trace/coresight/coresight-config.rst create mode 100644 drivers/hwtracing/coresight/coresight-cfg-preload.c create mode 100644 drivers/hwtracing/coresight/coresight-config.c create mode 100644 drivers/hwtracing/coresight/coresight-config.h create mode 100644 drivers/hwtracing/coresight/coresight-etm4x-cfg.c create mode 100644 drivers/hwtracing/coresight/coresight-etm4x-cfg.h create mode 100644 drivers/hwtracing/coresight/coresight-syscfg-configfs.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg-configfs.h create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.h
Creates an system management API to allow complex configurations and features to be programmed into a CoreSight infrastructure.
A feature is defined as a programming set for a device or class of devices.
A configuration is a set of features across the system that are enabled for a trace session.
The API will manage system wide configuration, and allow complex programmed features to be added to individual device instances, and provide for system wide configuration selection on trace capture operations.
This patch creates the initial data object and the initial API for loading configurations and features.
Signed-off-by: Mike Leach mike.leach@linaro.org --- drivers/hwtracing/coresight/Makefile | 2 +- .../hwtracing/coresight/coresight-config.h | 170 ++++++++++++ drivers/hwtracing/coresight/coresight-core.c | 12 +- .../hwtracing/coresight/coresight-etm-perf.c | 2 +- .../hwtracing/coresight/coresight-etm-perf.h | 2 +- .../hwtracing/coresight/coresight-syscfg.c | 247 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 57 ++++ 7 files changed, 488 insertions(+), 4 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-config.h create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.h
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index f20e357758d1..4ce854c434b1 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -4,7 +4,7 @@ # obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \ - coresight-sysfs.o + coresight-sysfs.o coresight-syscfg.o obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h new file mode 100644 index 000000000000..0d9ae1dc4517 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -0,0 +1,170 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Linaro Limited, All rights reserved. + * Author: Mike Leach mike.leach@linaro.org + */ + +#ifndef _CORESIGHT_CORESIGHT_CONFIG_H +#define _CORESIGHT_CORESIGHT_CONFIG_H + +#include <linux/coresight.h> +#include <linux/types.h> + +/* CoreSight Configuration - complex component and system config handling */ + +/* generic register flags */ +#define CS_CFG_REG_STD 0x80000000 /* reg is standard reg */ +#define CS_CFG_REG_RESOURCE 0x40000000 /* reg is a resource */ +#define CS_CFG_REG_VAL_PARAM 0x08000000 /* reg value uses param */ +#define CS_CFG_REG_VAL_MASK 0x04000000 /* reg value bit masked */ +#define CS_CFG_REG_VAL_64BIT 0x02000000 /* reg value 64 bit */ +#define CS_CFG_REG_VAL_SAVE 0x01000000 /* reg value save on disable */ +#define CS_CFG_REG_ID_MASK 0x00000FFF /* reg offset / id in device */ +#define CS_CFG_REG_DEV_MASK 0x00FFF000 /* device specific flags */ + +/* + * flags defining what device class a feature will match to when processing a + * system configuration - used by config data and devices. + */ +#define CS_CFG_MATCH_CLASS_SRC_ALL 0x0001 /* match any source */ +#define CS_CFG_MATCH_CLASS_SRC_ETM4 0x0002 /* match any ETMv4 device */ +#define CS_CFG_MATCH_CLASS_CTI_ALL 0x0004 /* match any CTI device */ +#define CS_CFG_MATCH_CLASS_CTI_CPU 0x0008 +#define CS_CFG_MATCH_CLASS_CTI_SYS 0x0010 + +/* flags defining device instance matching - used in config data. */ +#define CS_CFG_MATCH_INST_ANY 0x80000000 /* any instance of a class */ +#define CS_CFG_MATCH_INST_AMBA_DEVICE 0x40000000 /* specific amba device */ + +/* + * Limit number of presets in a configuration + * This is related to the number of bits (4) we use to select the preset on + * the perf command line. Preset 0 is always none selected. + * See PMU_FORMAT_ATTR(preset, "config:0-3") in coresight-etm-perf.c + */ +#define CS_CFG_CONFIG_PRESET_MAX 15 + + +/** + * Parameter descriptor for a device feature. + * + * @name: Name of parameter. + * @value: Initial or default value. + */ +struct cscfg_parameter_desc { + const char *name; + u64 value; +}; + +/** + * Representation of register value. + * + * Supports full 64 bit register value, or 32 bit value with optional mask + * value. + * + * @flags: define value usage as 32bit, 32bit+mask or 64bit. + * @val64: 64 bit value. + * @val32: 32 bit value. + * @mask32: 32 bit mask when using 32 bit value to access device register. + */ +struct cscfg_regval { + u32 flags; + union { + u64 val64; + struct { + u32 val32; + u32 mask32; + }; + }; +}; + + +/** + * Device feature descriptor - combination of registers and parameters to + * program a device to implement a specific complex function. + * + * @name: feature name. + * @brief: brief description of the feature. + * @item: List entry. + * @match_flags: matching information if loading into a device + * @nr_params: number of parameters used. + * @params: array of parameters used. + * @nr_regs: number of registers used. + * @reg: array of registers used. + */ +struct cscfg_feature_desc { + const char *name; + const char *brief; + struct list_head item; + u32 match_flags; + int nr_params; + struct cscfg_parameter_desc *params; + int nr_regs; + struct cscfg_regval *regs; +}; + +/** + * Device / feature matching information. + * + * Used by loading configurations to define which class or specific devices + * they want to match used features to, and registered devices to specify which + * matching class and information they support. + * The load process uses these matching pairs to load feature instances into + * matching devices. + * + * @match_flags: used to match to a particular class of device. + * @dev_name: used to match to a particular device instance on the system. + * + */ +struct cscfg_match_info { + u32 match_flags; + /* unique device name (e.g. amba bus name) for specific device match */ + const char *dev_name; +}; + +/** + * Descriptor for features referenced by a configuration. + * + * @name: name of feature to use. Match against the @name in struct + * cscfg_feature_desc. + * @nr_params: number of parameters the feature has. + * @match: match info for the feature when used in this configuration - + * may be all devices of a class or a specific device in that class. + */ +struct cscfg_config_feat_ref { + const char *name; + int nr_params; + struct cscfg_match_info match; +}; + +/** + * Configuration descriptor - describes selectable system configuration. + * + * A configuration describes device features in use, and may provide preset + * values for the parameters in those features. + * + * A single set of presets is the sum of the parameters declared by + * all the features in use - this value is @nr_total_params. + * + * @name: name of the configuration - used for selection. + * @brief: description of the purpose of the configuration. + * @item: list entry. + * @nr_refs: Number of features used in this configuration. + * @refs: references to features used in this configuration.. + * @nr_presets: Number of sets of presets supplied by this configuration. + * @nr_total_params: Sum of all parameters declared by used features + * @presets: Array of preset values. + * + */ +struct cscfg_config_desc { + const char *name; + const char *brief; + struct list_head item; + int nr_refs; + struct cscfg_config_feat_ref *refs; + int nr_presets; + int nr_total_params; + const u64 *presets; /* nr_presets * nr_total_params */ +}; + +#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 29c83eac3106..481d2b7b6b6f 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -21,6 +21,7 @@
#include "coresight-etm-perf.h" #include "coresight-priv.h" +#include "coresight-syscfg.h"
static DEFINE_MUTEX(coresight_mutex);
@@ -1675,13 +1676,22 @@ static int __init coresight_init(void)
ret = etm_perf_init(); if (ret) - bus_unregister(&coresight_bustype); + goto exit_bus_unregister;
+ /* initialise the coresight syscfg API */ + ret = cscfg_init(); + if (!ret) + return 0; + + etm_perf_exit(); +exit_bus_unregister: + bus_unregister(&coresight_bustype); return ret; }
static void __exit coresight_exit(void) { + cscfg_exit(); etm_perf_exit(); bus_unregister(&coresight_bustype); } diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index bdc34ca449f7..a608081bd446 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -627,7 +627,7 @@ int __init etm_perf_init(void) return ret; }
-void __exit etm_perf_exit(void) +void etm_perf_exit(void) { perf_pmu_unregister(&etm_pmu); } diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.h b/drivers/hwtracing/coresight/coresight-etm-perf.h index 3e4f2ad5e193..29d90dfeba31 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.h +++ b/drivers/hwtracing/coresight/coresight-etm-perf.h @@ -83,6 +83,6 @@ static inline void *etm_perf_sink_config(struct perf_output_handle *handle) #endif /* CONFIG_CORESIGHT */
int __init etm_perf_init(void); -void __exit etm_perf_exit(void); +void etm_perf_exit(void);
#endif diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c new file mode 100644 index 000000000000..6f89541af7a0 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Linaro Limited, All rights reserved. + * Author: Mike Leach mike.leach@linaro.org + */ + +#include <linux/platform_device.h> + +#include "coresight-config.h" +#include "coresight-syscfg.h" + +/* + * cscfg_ API manages configurations and features for the entire coresight + * infrastructure. + * + * It allows the loading of configurations and features, and loads these into + * coresight devices as appropriate. + */ + +static DEFINE_MUTEX(cscfg_mutex); + +/* only one of these */ +static struct cscfg_api_data cscfg_data; + +/* get reference to cscfg device */ +struct device *to_device_cscfg(void); + +/* load features and configuations into the lists */ + +/* check feature list for a named feature - call with mutex locked. */ +static bool cscfg_match_list_feat(const char *name) +{ + struct cscfg_feature_desc *curr_item; + + list_for_each_entry(curr_item, &cscfg_data.feat_list, item) { + if (strcmp(curr_item->name, name) == 0) + return true; + } + return false; +} + +/* check all feat needed for cfg are in the list - call with mutex locked. */ +static int cscfg_check_feat_for_cfg(struct cscfg_config_desc *cfg_desc) +{ + int i; + + for (i = 0; i < cfg_desc->nr_refs; i++) + if (!cscfg_match_list_feat(cfg_desc->refs[i].name)) + return -EINVAL; + return 0; +} + +/* + * load feature - add to feature list. + */ +static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc) +{ + list_add(&feat_desc->item, &cscfg_data.feat_list); + + return 0; +} + +/* + * load config into the system - validate used features exist then add to + * config list. + */ +static int cscfg_load_config(struct cscfg_config_desc *cfg_desc) +{ + int err; + + /* validate features are present */ + err = cscfg_check_feat_for_cfg(cfg_desc); + if (err) + return err; + + list_add(&cfg_desc->item, &cscfg_data.config_list); + + return 0; +} + +/* + * External API function to load feature and config sets. + * Take a 0 terminated array of feature descriptors and/or configuration + * descriptors and load into the system. + * Features are loaded first to ensure configuration dependencies can be met. + */ +int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, + struct cscfg_feature_desc **feat_descs) +{ + int err, i = 0; + + mutex_lock(&cscfg_mutex); + + /* load features first */ + if (feat_descs) { + while (feat_descs[i]) { + err = cscfg_load_feat(feat_descs[i]); + if (err) { + pr_err("coresight-syscfg: Failed to load feature %s\n", + feat_descs[i]->name); + goto do_unlock; + } + i++; + } + } + + /* next any configurations to check feature dependencies */ + i = 0; + if (cfg_descs) { + while (cfg_descs[i]) { + err = cscfg_load_config(cfg_descs[i]); + if (err) { + pr_err("coresight-syscfg: Failed to load configuration %s\n", + cfg_descs[i]->name); + goto do_unlock; + } + i++; + } + } + +do_unlock: + mutex_unlock(&cscfg_mutex); + return err; +} +EXPORT_SYMBOL_GPL(cscfg_load_config_sets); + +/* Initialise system configuration management driver. */ +/* only one of these */ +static struct cscfg_device *cscfg_dev; + +/* + * We have a separate coresight-config bus for the config device so it does + * not appear on the main coresight bus and affect device searches on that bus. + */ +static struct bus_type cscfg_bus_type = { + .name = "coresight-config", +}; + +struct device *to_device_cscfg(void) +{ + return cscfg_dev ? &cscfg_dev->dev : NULL; +} + +/* Must have a release function or the kernel will complain on module unload */ +void cscfg_dev_release(struct device *dev) +{ + kfree(cscfg_dev); + cscfg_dev = NULL; +} + +int cscfg_create_device(void) +{ + struct device *dev; + int err = -ENOMEM; + + mutex_lock(&cscfg_mutex); + if (cscfg_dev) { + err = -EINVAL; + goto create_dev_exit_unlock; + } + + cscfg_dev = kzalloc(sizeof(struct cscfg_device), GFP_KERNEL); + if (!cscfg_dev) + goto create_dev_exit_unlock; + + /* setup the device */ + dev = to_device_cscfg(); + dev->bus = &cscfg_bus_type; + dev->parent = &platform_bus; + dev->release = cscfg_dev_release; + dev->init_name = "system_cfg"; + cscfg_dev->cfg_data = &cscfg_data; + + err = device_register(dev); + if (err) + cscfg_dev_release(dev); + +create_dev_exit_unlock: + mutex_unlock(&cscfg_mutex); + return err; +} + +void cscfg_clear_device(void) +{ + mutex_lock(&cscfg_mutex); + device_unregister(to_device_cscfg()); + mutex_unlock(&cscfg_mutex); +} + +/* driver initialisation */ +static struct cscfg_driver cs_config_driver = { + .drv = { + .name = "cs-syscfg-drv", + .owner = THIS_MODULE, + .suppress_bind_attrs = true, + }, +}; + +int __init cscfg_driver_init(void) +{ + cs_config_driver.drv.bus = &cscfg_bus_type; + return driver_register(&cs_config_driver.drv); +} + +void cscfg_driver_exit(void) +{ + driver_unregister(&cs_config_driver.drv); +} + +/* Initialise system config management API */ +int __init cscfg_init(void) +{ + int err = 0; + + err = bus_register(&cscfg_bus_type); + if (err) + return err; + + err = cscfg_driver_init(); + if (err) + goto exit_bus_unregister; + + err = cscfg_create_device(); + if (err) + goto exit_drv_unregister; + + INIT_LIST_HEAD(&cscfg_data.dev_list); + INIT_LIST_HEAD(&cscfg_data.feat_list); + INIT_LIST_HEAD(&cscfg_data.config_list); + cscfg_data.nr_csdev = 0; + + dev_info(to_device_cscfg(), "CoreSight Configuration manager initialised"); + return 0; + +exit_drv_unregister: + cscfg_driver_exit(); +exit_bus_unregister: + bus_unregister(&cscfg_bus_type); + return err; +} + +void __exit cscfg_exit(void) +{ + cscfg_clear_device(); + cscfg_driver_exit(); + bus_unregister(&cscfg_bus_type); +} diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h new file mode 100644 index 000000000000..5a7896426eab --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Coresight system configuration driver. + */ + +#ifndef CORESIGHT_SYSCFG_H +#define CORESIGHT_SYSCFG_H + +#include <linux/coresight.h> +#include <linux/device.h> + +#include "coresight-config.h" + +/** + * System configuration API data. + * + * @dev_list: List of other coresight devices registered with this device. + * @feat_list: List of features to load into registered devices. + * @config_list:List of system configurations to load into registered devices. + * @nr_csdev: Number of registered devices with the cscfg system + */ +struct cscfg_api_data { + struct list_head dev_list; + struct list_head feat_list; + struct list_head config_list; + int nr_csdev; +}; + +/* internal core operations for cscfg */ +int __init cscfg_init(void); +void __exit cscfg_exit(void); + +/* syscfg external API */ +int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, + struct cscfg_feature_desc **feat_descs); + +/* system configuration device driver and API */ +/** + * System configuration device. + * + * Need a device to 'own' some coresight system wide sysfs entries in + * perf events etc. + * + * @dev: The device. + * @cfg_data: A reference to the configuration and feature lists + */ +struct cscfg_device { + struct device dev; + struct cscfg_api_data *cfg_data; +}; + +/* basic device driver */ +struct cscfg_driver { + struct device_driver drv; +}; + +#endif /* CORESIGHT_SYSCFG_H */
Good day,
I have started looking at this patchset yesterday - the documentation really helps. As usual comments will be staggered over several days. Some can be found below.
On Fri, Oct 30, 2020 at 05:56:47PM +0000, Mike Leach wrote:
Creates an system management API to allow complex configurations and features to be programmed into a CoreSight infrastructure.
A feature is defined as a programming set for a device or class of devices.
A configuration is a set of features across the system that are enabled for a trace session.
The API will manage system wide configuration, and allow complex programmed features to be added to individual device instances, and provide for system wide configuration selection on trace capture operations.
This patch creates the initial data object and the initial API for loading configurations and features.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 2 +- .../hwtracing/coresight/coresight-config.h | 170 ++++++++++++ drivers/hwtracing/coresight/coresight-core.c | 12 +- .../hwtracing/coresight/coresight-etm-perf.c | 2 +- .../hwtracing/coresight/coresight-etm-perf.h | 2 +- .../hwtracing/coresight/coresight-syscfg.c | 247 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 57 ++++ 7 files changed, 488 insertions(+), 4 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-config.h create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.h
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index f20e357758d1..4ce854c434b1 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -4,7 +4,7 @@ # obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \
coresight-sysfs.o
coresight-sysfs.o coresight-syscfg.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h new file mode 100644 index 000000000000..0d9ae1dc4517 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -0,0 +1,170 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#ifndef _CORESIGHT_CORESIGHT_CONFIG_H +#define _CORESIGHT_CORESIGHT_CONFIG_H
+#include <linux/coresight.h> +#include <linux/types.h>
+/* CoreSight Configuration - complex component and system config handling */
+/* generic register flags */ +#define CS_CFG_REG_STD 0x80000000 /* reg is standard reg */ +#define CS_CFG_REG_RESOURCE 0x40000000 /* reg is a resource */ +#define CS_CFG_REG_VAL_PARAM 0x08000000 /* reg value uses param */ +#define CS_CFG_REG_VAL_MASK 0x04000000 /* reg value bit masked */ +#define CS_CFG_REG_VAL_64BIT 0x02000000 /* reg value 64 bit */ +#define CS_CFG_REG_VAL_SAVE 0x01000000 /* reg value save on disable */ +#define CS_CFG_REG_ID_MASK 0x00000FFF /* reg offset / id in device */ +#define CS_CFG_REG_DEV_MASK 0x00FFF000 /* device specific flags */
+/*
- flags defining what device class a feature will match to when processing a
- system configuration - used by config data and devices.
- */
+#define CS_CFG_MATCH_CLASS_SRC_ALL 0x0001 /* match any source */ +#define CS_CFG_MATCH_CLASS_SRC_ETM4 0x0002 /* match any ETMv4 device */ +#define CS_CFG_MATCH_CLASS_CTI_ALL 0x0004 /* match any CTI device */ +#define CS_CFG_MATCH_CLASS_CTI_CPU 0x0008 +#define CS_CFG_MATCH_CLASS_CTI_SYS 0x0010
+/* flags defining device instance matching - used in config data. */ +#define CS_CFG_MATCH_INST_ANY 0x80000000 /* any instance of a class */ +#define CS_CFG_MATCH_INST_AMBA_DEVICE 0x40000000 /* specific amba device */
Is there a real need for the above two in this set? As far as I can tell the etmv4 and CTI flags would be enough.
+/*
- Limit number of presets in a configuration
- This is related to the number of bits (4) we use to select the preset on
- the perf command line. Preset 0 is always none selected.
- See PMU_FORMAT_ATTR(preset, "config:0-3") in coresight-etm-perf.c
- */
+#define CS_CFG_CONFIG_PRESET_MAX 15
Extra line
+/**
- Parameter descriptor for a device feature.
- @name: Name of parameter.
- @value: Initial or default value.
- */
+struct cscfg_parameter_desc {
- const char *name;
- u64 value;
+};
+/**
- Representation of register value.
- Supports full 64 bit register value, or 32 bit value with optional mask
- value.
- @flags: define value usage as 32bit, 32bit+mask or 64bit.
- @val64: 64 bit value.
- @val32: 32 bit value.
- @mask32: 32 bit mask when using 32 bit value to access device register.
- */
+struct cscfg_regval {
- u32 flags;
This field has to be unpacked, i.e
u16 flags; u16 address;
Otherwise it is impossible to understand what a cscfg_regval is. Moreover I'm worried about the "flags" and all the possible values. We have to think about how people will be using this thing and right now it is difficult.
- union {
u64 val64;
struct {
u32 val32;
u32 mask32;
};
- };
+};
Extra line
+/**
- Device feature descriptor - combination of registers and parameters to
- program a device to implement a specific complex function.
- @name: feature name.
- @brief: brief description of the feature.
- @item: List entry.
- @match_flags: matching information if loading into a device
- @nr_params: number of parameters used.
- @params: array of parameters used.
- @nr_regs: number of registers used.
- @reg: array of registers used.
- */
+struct cscfg_feature_desc {
- const char *name;
- const char *brief;
- struct list_head item;
- u32 match_flags;
- int nr_params;
- struct cscfg_parameter_desc *params;
- int nr_regs;
- struct cscfg_regval *regs;
+};
+/**
- Device / feature matching information.
- Used by loading configurations to define which class or specific devices
- they want to match used features to, and registered devices to specify which
- matching class and information they support.
- The load process uses these matching pairs to load feature instances into
- matching devices.
- @match_flags: used to match to a particular class of device.
- @dev_name: used to match to a particular device instance on the system.
- */
+struct cscfg_match_info {
- u32 match_flags;
- /* unique device name (e.g. amba bus name) for specific device match */
- const char *dev_name;
Again I'm not sure there is an immediate need for *dev_name in this set. Just having a match_flag in cscfg_config_feat_ref would be enough.
+};
+/**
- Descriptor for features referenced by a configuration.
- @name: name of feature to use. Match against the @name in struct
cscfg_feature_desc.
- @nr_params: number of parameters the feature has.
- @match: match info for the feature when used in this configuration -
may be all devices of a class or a specific device in that class.
- */
+struct cscfg_config_feat_ref {
- const char *name;
- int nr_params;
It is possible, using *name, to get to the cscfg_feature_desc where nr_params is defined. Looking at patch 06, having nr_params here is duplicating the information already available in cscfg_feature_desc - can it be removed completely?
- struct cscfg_match_info match;
+};
+/**
- Configuration descriptor - describes selectable system configuration.
- A configuration describes device features in use, and may provide preset
- values for the parameters in those features.
- A single set of presets is the sum of the parameters declared by
- all the features in use - this value is @nr_total_params.
- @name: name of the configuration - used for selection.
- @brief: description of the purpose of the configuration.
- @item: list entry.
- @nr_refs: Number of features used in this configuration.
- @refs: references to features used in this configuration..
- @nr_presets: Number of sets of presets supplied by this configuration.
- @nr_total_params: Sum of all parameters declared by used features
- @presets: Array of preset values.
Extra line
- */
+struct cscfg_config_desc {
- const char *name;
- const char *brief;
- struct list_head item;
- int nr_refs;
- struct cscfg_config_feat_ref *refs;
- int nr_presets;
- int nr_total_params;
- const u64 *presets; /* nr_presets * nr_total_params */
In this patchset the presets are easy because autofdo has a single feature and there is only 2 parameters for this feature. I worry about what things will look like when a configuration has 6 featurse, each with a varying number of parameters. Here too I don't have a clear answer on how to proceed but it will need to be revised.
+};
Aligning the name of the structures in this file has really helped, thanks for doing that.
More comments to come.
Thanks, Mathieu
+#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 29c83eac3106..481d2b7b6b6f 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -21,6 +21,7 @@ #include "coresight-etm-perf.h" #include "coresight-priv.h" +#include "coresight-syscfg.h" static DEFINE_MUTEX(coresight_mutex); @@ -1675,13 +1676,22 @@ static int __init coresight_init(void) ret = etm_perf_init(); if (ret)
bus_unregister(&coresight_bustype);
goto exit_bus_unregister;
- /* initialise the coresight syscfg API */
- ret = cscfg_init();
- if (!ret)
return 0;
- etm_perf_exit();
+exit_bus_unregister:
- bus_unregister(&coresight_bustype); return ret;
} static void __exit coresight_exit(void) {
- cscfg_exit(); etm_perf_exit(); bus_unregister(&coresight_bustype);
} diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index bdc34ca449f7..a608081bd446 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -627,7 +627,7 @@ int __init etm_perf_init(void) return ret; } -void __exit etm_perf_exit(void) +void etm_perf_exit(void) { perf_pmu_unregister(&etm_pmu); } diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.h b/drivers/hwtracing/coresight/coresight-etm-perf.h index 3e4f2ad5e193..29d90dfeba31 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.h +++ b/drivers/hwtracing/coresight/coresight-etm-perf.h @@ -83,6 +83,6 @@ static inline void *etm_perf_sink_config(struct perf_output_handle *handle) #endif /* CONFIG_CORESIGHT */ int __init etm_perf_init(void); -void __exit etm_perf_exit(void); +void etm_perf_exit(void); #endif diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c new file mode 100644 index 000000000000..6f89541af7a0 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <linux/platform_device.h>
+#include "coresight-config.h" +#include "coresight-syscfg.h"
+/*
- cscfg_ API manages configurations and features for the entire coresight
- infrastructure.
- It allows the loading of configurations and features, and loads these into
- coresight devices as appropriate.
- */
+static DEFINE_MUTEX(cscfg_mutex);
+/* only one of these */ +static struct cscfg_api_data cscfg_data;
+/* get reference to cscfg device */ +struct device *to_device_cscfg(void);
+/* load features and configuations into the lists */
+/* check feature list for a named feature - call with mutex locked. */ +static bool cscfg_match_list_feat(const char *name) +{
- struct cscfg_feature_desc *curr_item;
- list_for_each_entry(curr_item, &cscfg_data.feat_list, item) {
if (strcmp(curr_item->name, name) == 0)
return true;
- }
- return false;
+}
+/* check all feat needed for cfg are in the list - call with mutex locked. */ +static int cscfg_check_feat_for_cfg(struct cscfg_config_desc *cfg_desc) +{
- int i;
- for (i = 0; i < cfg_desc->nr_refs; i++)
if (!cscfg_match_list_feat(cfg_desc->refs[i].name))
return -EINVAL;
- return 0;
+}
+/*
- load feature - add to feature list.
- */
+static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc) +{
- list_add(&feat_desc->item, &cscfg_data.feat_list);
- return 0;
+}
+/*
- load config into the system - validate used features exist then add to
- config list.
- */
+static int cscfg_load_config(struct cscfg_config_desc *cfg_desc) +{
- int err;
- /* validate features are present */
- err = cscfg_check_feat_for_cfg(cfg_desc);
- if (err)
return err;
- list_add(&cfg_desc->item, &cscfg_data.config_list);
- return 0;
+}
+/*
- External API function to load feature and config sets.
- Take a 0 terminated array of feature descriptors and/or configuration
- descriptors and load into the system.
- Features are loaded first to ensure configuration dependencies can be met.
- */
+int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs,
struct cscfg_feature_desc **feat_descs)
+{
- int err, i = 0;
- mutex_lock(&cscfg_mutex);
- /* load features first */
- if (feat_descs) {
while (feat_descs[i]) {
err = cscfg_load_feat(feat_descs[i]);
if (err) {
pr_err("coresight-syscfg: Failed to load feature %s\n",
feat_descs[i]->name);
goto do_unlock;
}
i++;
}
- }
- /* next any configurations to check feature dependencies */
- i = 0;
- if (cfg_descs) {
while (cfg_descs[i]) {
err = cscfg_load_config(cfg_descs[i]);
if (err) {
pr_err("coresight-syscfg: Failed to load configuration %s\n",
cfg_descs[i]->name);
goto do_unlock;
}
i++;
}
- }
+do_unlock:
- mutex_unlock(&cscfg_mutex);
- return err;
+} +EXPORT_SYMBOL_GPL(cscfg_load_config_sets);
+/* Initialise system configuration management driver. */ +/* only one of these */ +static struct cscfg_device *cscfg_dev;
+/*
- We have a separate coresight-config bus for the config device so it does
- not appear on the main coresight bus and affect device searches on that bus.
- */
+static struct bus_type cscfg_bus_type = {
- .name = "coresight-config",
+};
+struct device *to_device_cscfg(void) +{
- return cscfg_dev ? &cscfg_dev->dev : NULL;
+}
+/* Must have a release function or the kernel will complain on module unload */ +void cscfg_dev_release(struct device *dev) +{
- kfree(cscfg_dev);
- cscfg_dev = NULL;
+}
+int cscfg_create_device(void) +{
- struct device *dev;
- int err = -ENOMEM;
- mutex_lock(&cscfg_mutex);
- if (cscfg_dev) {
err = -EINVAL;
goto create_dev_exit_unlock;
- }
- cscfg_dev = kzalloc(sizeof(struct cscfg_device), GFP_KERNEL);
- if (!cscfg_dev)
goto create_dev_exit_unlock;
- /* setup the device */
- dev = to_device_cscfg();
- dev->bus = &cscfg_bus_type;
- dev->parent = &platform_bus;
- dev->release = cscfg_dev_release;
- dev->init_name = "system_cfg";
- cscfg_dev->cfg_data = &cscfg_data;
- err = device_register(dev);
- if (err)
cscfg_dev_release(dev);
+create_dev_exit_unlock:
- mutex_unlock(&cscfg_mutex);
- return err;
+}
+void cscfg_clear_device(void) +{
- mutex_lock(&cscfg_mutex);
- device_unregister(to_device_cscfg());
- mutex_unlock(&cscfg_mutex);
+}
+/* driver initialisation */ +static struct cscfg_driver cs_config_driver = {
- .drv = {
.name = "cs-syscfg-drv",
.owner = THIS_MODULE,
.suppress_bind_attrs = true,
- },
+};
+int __init cscfg_driver_init(void) +{
- cs_config_driver.drv.bus = &cscfg_bus_type;
- return driver_register(&cs_config_driver.drv);
+}
+void cscfg_driver_exit(void) +{
- driver_unregister(&cs_config_driver.drv);
+}
+/* Initialise system config management API */ +int __init cscfg_init(void) +{
- int err = 0;
- err = bus_register(&cscfg_bus_type);
- if (err)
return err;
- err = cscfg_driver_init();
- if (err)
goto exit_bus_unregister;
- err = cscfg_create_device();
- if (err)
goto exit_drv_unregister;
- INIT_LIST_HEAD(&cscfg_data.dev_list);
- INIT_LIST_HEAD(&cscfg_data.feat_list);
- INIT_LIST_HEAD(&cscfg_data.config_list);
- cscfg_data.nr_csdev = 0;
- dev_info(to_device_cscfg(), "CoreSight Configuration manager initialised");
- return 0;
+exit_drv_unregister:
- cscfg_driver_exit();
+exit_bus_unregister:
- bus_unregister(&cscfg_bus_type);
- return err;
+}
+void __exit cscfg_exit(void) +{
- cscfg_clear_device();
- cscfg_driver_exit();
- bus_unregister(&cscfg_bus_type);
+} diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h new file mode 100644 index 000000000000..5a7896426eab --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/*
- Coresight system configuration driver.
- */
+#ifndef CORESIGHT_SYSCFG_H +#define CORESIGHT_SYSCFG_H
+#include <linux/coresight.h> +#include <linux/device.h>
+#include "coresight-config.h"
+/**
- System configuration API data.
- @dev_list: List of other coresight devices registered with this device.
- @feat_list: List of features to load into registered devices.
- @config_list:List of system configurations to load into registered devices.
- @nr_csdev: Number of registered devices with the cscfg system
- */
+struct cscfg_api_data {
- struct list_head dev_list;
- struct list_head feat_list;
- struct list_head config_list;
- int nr_csdev;
+};
+/* internal core operations for cscfg */ +int __init cscfg_init(void); +void __exit cscfg_exit(void);
+/* syscfg external API */ +int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs,
struct cscfg_feature_desc **feat_descs);
+/* system configuration device driver and API */ +/**
- System configuration device.
- Need a device to 'own' some coresight system wide sysfs entries in
- perf events etc.
- @dev: The device.
- @cfg_data: A reference to the configuration and feature lists
- */
+struct cscfg_device {
- struct device dev;
- struct cscfg_api_data *cfg_data;
+};
+/* basic device driver */ +struct cscfg_driver {
- struct device_driver drv;
+};
+#endif /* CORESIGHT_SYSCFG_H */
2.17.1
On Fri, Oct 30, 2020 at 05:56:47PM +0000, Mike Leach wrote:
Creates an system management API to allow complex configurations and features to be programmed into a CoreSight infrastructure.
A feature is defined as a programming set for a device or class of devices.
A configuration is a set of features across the system that are enabled for a trace session.
The API will manage system wide configuration, and allow complex programmed features to be added to individual device instances, and provide for system wide configuration selection on trace capture operations.
This patch creates the initial data object and the initial API for loading configurations and features.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 2 +- .../hwtracing/coresight/coresight-config.h | 170 ++++++++++++ drivers/hwtracing/coresight/coresight-core.c | 12 +- .../hwtracing/coresight/coresight-etm-perf.c | 2 +- .../hwtracing/coresight/coresight-etm-perf.h | 2 +- .../hwtracing/coresight/coresight-syscfg.c | 247 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 57 ++++ 7 files changed, 488 insertions(+), 4 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-config.h create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.h
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index f20e357758d1..4ce854c434b1 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -4,7 +4,7 @@ # obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \
coresight-sysfs.o
coresight-sysfs.o coresight-syscfg.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h new file mode 100644 index 000000000000..0d9ae1dc4517 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -0,0 +1,170 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#ifndef _CORESIGHT_CORESIGHT_CONFIG_H +#define _CORESIGHT_CORESIGHT_CONFIG_H
+#include <linux/coresight.h> +#include <linux/types.h>
+/* CoreSight Configuration - complex component and system config handling */
+/* generic register flags */ +#define CS_CFG_REG_STD 0x80000000 /* reg is standard reg */ +#define CS_CFG_REG_RESOURCE 0x40000000 /* reg is a resource */ +#define CS_CFG_REG_VAL_PARAM 0x08000000 /* reg value uses param */ +#define CS_CFG_REG_VAL_MASK 0x04000000 /* reg value bit masked */ +#define CS_CFG_REG_VAL_64BIT 0x02000000 /* reg value 64 bit */ +#define CS_CFG_REG_VAL_SAVE 0x01000000 /* reg value save on disable */ +#define CS_CFG_REG_ID_MASK 0x00000FFF /* reg offset / id in device */ +#define CS_CFG_REG_DEV_MASK 0x00FFF000 /* device specific flags */
+/*
- flags defining what device class a feature will match to when processing a
- system configuration - used by config data and devices.
- */
+#define CS_CFG_MATCH_CLASS_SRC_ALL 0x0001 /* match any source */ +#define CS_CFG_MATCH_CLASS_SRC_ETM4 0x0002 /* match any ETMv4 device */ +#define CS_CFG_MATCH_CLASS_CTI_ALL 0x0004 /* match any CTI device */ +#define CS_CFG_MATCH_CLASS_CTI_CPU 0x0008 +#define CS_CFG_MATCH_CLASS_CTI_SYS 0x0010
+/* flags defining device instance matching - used in config data. */ +#define CS_CFG_MATCH_INST_ANY 0x80000000 /* any instance of a class */ +#define CS_CFG_MATCH_INST_AMBA_DEVICE 0x40000000 /* specific amba device */
+/*
- Limit number of presets in a configuration
- This is related to the number of bits (4) we use to select the preset on
- the perf command line. Preset 0 is always none selected.
- See PMU_FORMAT_ATTR(preset, "config:0-3") in coresight-etm-perf.c
- */
+#define CS_CFG_CONFIG_PRESET_MAX 15
+/**
- Parameter descriptor for a device feature.
- @name: Name of parameter.
- @value: Initial or default value.
- */
+struct cscfg_parameter_desc {
- const char *name;
- u64 value;
+};
+/**
- Representation of register value.
- Supports full 64 bit register value, or 32 bit value with optional mask
- value.
- @flags: define value usage as 32bit, 32bit+mask or 64bit.
- @val64: 64 bit value.
- @val32: 32 bit value.
- @mask32: 32 bit mask when using 32 bit value to access device register.
- */
+struct cscfg_regval {
- u32 flags;
- union {
u64 val64;
struct {
u32 val32;
u32 mask32;
};
- };
+};
+/**
- Device feature descriptor - combination of registers and parameters to
- program a device to implement a specific complex function.
- @name: feature name.
- @brief: brief description of the feature.
- @item: List entry.
- @match_flags: matching information if loading into a device
- @nr_params: number of parameters used.
- @params: array of parameters used.
- @nr_regs: number of registers used.
- @reg: array of registers used.
- */
+struct cscfg_feature_desc {
- const char *name;
- const char *brief;
- struct list_head item;
- u32 match_flags;
- int nr_params;
- struct cscfg_parameter_desc *params;
- int nr_regs;
- struct cscfg_regval *regs;
+};
+/**
- Device / feature matching information.
- Used by loading configurations to define which class or specific devices
- they want to match used features to, and registered devices to specify which
- matching class and information they support.
- The load process uses these matching pairs to load feature instances into
- matching devices.
- @match_flags: used to match to a particular class of device.
- @dev_name: used to match to a particular device instance on the system.
- */
+struct cscfg_match_info {
- u32 match_flags;
- /* unique device name (e.g. amba bus name) for specific device match */
- const char *dev_name;
+};
+/**
- Descriptor for features referenced by a configuration.
- @name: name of feature to use. Match against the @name in struct
cscfg_feature_desc.
- @nr_params: number of parameters the feature has.
- @match: match info for the feature when used in this configuration -
may be all devices of a class or a specific device in that class.
- */
+struct cscfg_config_feat_ref {
- const char *name;
- int nr_params;
- struct cscfg_match_info match;
+};
+/**
- Configuration descriptor - describes selectable system configuration.
- A configuration describes device features in use, and may provide preset
- values for the parameters in those features.
- A single set of presets is the sum of the parameters declared by
- all the features in use - this value is @nr_total_params.
- @name: name of the configuration - used for selection.
- @brief: description of the purpose of the configuration.
- @item: list entry.
- @nr_refs: Number of features used in this configuration.
- @refs: references to features used in this configuration..
- @nr_presets: Number of sets of presets supplied by this configuration.
- @nr_total_params: Sum of all parameters declared by used features
- @presets: Array of preset values.
- */
+struct cscfg_config_desc {
- const char *name;
- const char *brief;
- struct list_head item;
- int nr_refs;
- struct cscfg_config_feat_ref *refs;
- int nr_presets;
- int nr_total_params;
- const u64 *presets; /* nr_presets * nr_total_params */
+};
+#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 29c83eac3106..481d2b7b6b6f 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -21,6 +21,7 @@ #include "coresight-etm-perf.h" #include "coresight-priv.h" +#include "coresight-syscfg.h" static DEFINE_MUTEX(coresight_mutex); @@ -1675,13 +1676,22 @@ static int __init coresight_init(void) ret = etm_perf_init(); if (ret)
bus_unregister(&coresight_bustype);
goto exit_bus_unregister;
- /* initialise the coresight syscfg API */
- ret = cscfg_init();
- if (!ret)
return 0;
- etm_perf_exit();
+exit_bus_unregister:
- bus_unregister(&coresight_bustype); return ret;
} static void __exit coresight_exit(void) {
- cscfg_exit(); etm_perf_exit(); bus_unregister(&coresight_bustype);
} diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index bdc34ca449f7..a608081bd446 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -627,7 +627,7 @@ int __init etm_perf_init(void) return ret; } -void __exit etm_perf_exit(void) +void etm_perf_exit(void) { perf_pmu_unregister(&etm_pmu); } diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.h b/drivers/hwtracing/coresight/coresight-etm-perf.h index 3e4f2ad5e193..29d90dfeba31 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.h +++ b/drivers/hwtracing/coresight/coresight-etm-perf.h @@ -83,6 +83,6 @@ static inline void *etm_perf_sink_config(struct perf_output_handle *handle) #endif /* CONFIG_CORESIGHT */ int __init etm_perf_init(void); -void __exit etm_perf_exit(void); +void etm_perf_exit(void); #endif diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c new file mode 100644 index 000000000000..6f89541af7a0 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <linux/platform_device.h>
+#include "coresight-config.h" +#include "coresight-syscfg.h"
+/*
- cscfg_ API manages configurations and features for the entire coresight
- infrastructure.
- It allows the loading of configurations and features, and loads these into
- coresight devices as appropriate.
- */
+static DEFINE_MUTEX(cscfg_mutex);
+/* only one of these */ +static struct cscfg_api_data cscfg_data;
+/* get reference to cscfg device */ +struct device *to_device_cscfg(void);
+/* load features and configuations into the lists */
+/* check feature list for a named feature - call with mutex locked. */ +static bool cscfg_match_list_feat(const char *name) +{
- struct cscfg_feature_desc *curr_item;
- list_for_each_entry(curr_item, &cscfg_data.feat_list, item) {
if (strcmp(curr_item->name, name) == 0)
return true;
- }
- return false;
+}
+/* check all feat needed for cfg are in the list - call with mutex locked. */ +static int cscfg_check_feat_for_cfg(struct cscfg_config_desc *cfg_desc) +{
- int i;
- for (i = 0; i < cfg_desc->nr_refs; i++)
if (!cscfg_match_list_feat(cfg_desc->refs[i].name))
return -EINVAL;
- return 0;
+}
+/*
- load feature - add to feature list.
- */
+static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc) +{
- list_add(&feat_desc->item, &cscfg_data.feat_list);
- return 0;
+}
+/*
- load config into the system - validate used features exist then add to
- config list.
- */
+static int cscfg_load_config(struct cscfg_config_desc *cfg_desc) +{
- int err;
- /* validate features are present */
- err = cscfg_check_feat_for_cfg(cfg_desc);
- if (err)
return err;
- list_add(&cfg_desc->item, &cscfg_data.config_list);
- return 0;
+}
+/*
- External API function to load feature and config sets.
- Take a 0 terminated array of feature descriptors and/or configuration
- descriptors and load into the system.
- Features are loaded first to ensure configuration dependencies can be met.
- */
+int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs,
struct cscfg_feature_desc **feat_descs)
+{
- int err, i = 0;
- mutex_lock(&cscfg_mutex);
- /* load features first */
- if (feat_descs) {
while (feat_descs[i]) {
err = cscfg_load_feat(feat_descs[i]);
if (err) {
pr_err("coresight-syscfg: Failed to load feature %s\n",
feat_descs[i]->name);
goto do_unlock;
}
i++;
}
- }
- /* next any configurations to check feature dependencies */
- i = 0;
- if (cfg_descs) {
while (cfg_descs[i]) {
err = cscfg_load_config(cfg_descs[i]);
if (err) {
pr_err("coresight-syscfg: Failed to load configuration %s\n",
cfg_descs[i]->name);
goto do_unlock;
}
i++;
}
- }
+do_unlock:
- mutex_unlock(&cscfg_mutex);
- return err;
+} +EXPORT_SYMBOL_GPL(cscfg_load_config_sets);
For file coresight-syscfg.c I am good with the top to here. I will comment further on what comes below at a later time.
+/* Initialise system configuration management driver. */ +/* only one of these */ +static struct cscfg_device *cscfg_dev;
+/*
- We have a separate coresight-config bus for the config device so it does
- not appear on the main coresight bus and affect device searches on that bus.
- */
+static struct bus_type cscfg_bus_type = {
- .name = "coresight-config",
+};
+struct device *to_device_cscfg(void) +{
- return cscfg_dev ? &cscfg_dev->dev : NULL;
+}
+/* Must have a release function or the kernel will complain on module unload */ +void cscfg_dev_release(struct device *dev) +{
- kfree(cscfg_dev);
- cscfg_dev = NULL;
+}
+int cscfg_create_device(void) +{
- struct device *dev;
- int err = -ENOMEM;
- mutex_lock(&cscfg_mutex);
- if (cscfg_dev) {
err = -EINVAL;
goto create_dev_exit_unlock;
- }
- cscfg_dev = kzalloc(sizeof(struct cscfg_device), GFP_KERNEL);
- if (!cscfg_dev)
goto create_dev_exit_unlock;
- /* setup the device */
- dev = to_device_cscfg();
- dev->bus = &cscfg_bus_type;
- dev->parent = &platform_bus;
- dev->release = cscfg_dev_release;
- dev->init_name = "system_cfg";
- cscfg_dev->cfg_data = &cscfg_data;
- err = device_register(dev);
- if (err)
cscfg_dev_release(dev);
+create_dev_exit_unlock:
- mutex_unlock(&cscfg_mutex);
- return err;
+}
+void cscfg_clear_device(void) +{
- mutex_lock(&cscfg_mutex);
- device_unregister(to_device_cscfg());
- mutex_unlock(&cscfg_mutex);
+}
+/* driver initialisation */ +static struct cscfg_driver cs_config_driver = {
- .drv = {
.name = "cs-syscfg-drv",
.owner = THIS_MODULE,
.suppress_bind_attrs = true,
- },
+};
+int __init cscfg_driver_init(void) +{
- cs_config_driver.drv.bus = &cscfg_bus_type;
- return driver_register(&cs_config_driver.drv);
+}
+void cscfg_driver_exit(void) +{
- driver_unregister(&cs_config_driver.drv);
+}
+/* Initialise system config management API */ +int __init cscfg_init(void) +{
- int err = 0;
- err = bus_register(&cscfg_bus_type);
- if (err)
return err;
- err = cscfg_driver_init();
- if (err)
goto exit_bus_unregister;
- err = cscfg_create_device();
- if (err)
goto exit_drv_unregister;
- INIT_LIST_HEAD(&cscfg_data.dev_list);
- INIT_LIST_HEAD(&cscfg_data.feat_list);
- INIT_LIST_HEAD(&cscfg_data.config_list);
- cscfg_data.nr_csdev = 0;
- dev_info(to_device_cscfg(), "CoreSight Configuration manager initialised");
- return 0;
+exit_drv_unregister:
- cscfg_driver_exit();
+exit_bus_unregister:
- bus_unregister(&cscfg_bus_type);
- return err;
+}
+void __exit cscfg_exit(void) +{
- cscfg_clear_device();
- cscfg_driver_exit();
- bus_unregister(&cscfg_bus_type);
+} diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h new file mode 100644 index 000000000000..5a7896426eab --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/*
- Coresight system configuration driver.
- */
+#ifndef CORESIGHT_SYSCFG_H +#define CORESIGHT_SYSCFG_H
+#include <linux/coresight.h> +#include <linux/device.h>
+#include "coresight-config.h"
+/**
- System configuration API data.
- @dev_list: List of other coresight devices registered with this device.
- @feat_list: List of features to load into registered devices.
- @config_list:List of system configurations to load into registered devices.
- @nr_csdev: Number of registered devices with the cscfg system
- */
+struct cscfg_api_data {
- struct list_head dev_list;
- struct list_head feat_list;
- struct list_head config_list;
- int nr_csdev;
+};
+/* internal core operations for cscfg */ +int __init cscfg_init(void); +void __exit cscfg_exit(void);
+/* syscfg external API */ +int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs,
struct cscfg_feature_desc **feat_descs);
+/* system configuration device driver and API */ +/**
- System configuration device.
- Need a device to 'own' some coresight system wide sysfs entries in
- perf events etc.
- @dev: The device.
- @cfg_data: A reference to the configuration and feature lists
- */
+struct cscfg_device {
- struct device dev;
- struct cscfg_api_data *cfg_data;
+};
+/* basic device driver */ +struct cscfg_driver {
- struct device_driver drv;
+};
+#endif /* CORESIGHT_SYSCFG_H */
2.17.1
On Fri, Oct 30, 2020 at 05:56:47PM +0000, Mike Leach wrote:
Creates an system management API to allow complex configurations and features to be programmed into a CoreSight infrastructure.
A feature is defined as a programming set for a device or class of devices.
A configuration is a set of features across the system that are enabled for a trace session.
The API will manage system wide configuration, and allow complex programmed features to be added to individual device instances, and provide for system wide configuration selection on trace capture operations.
This patch creates the initial data object and the initial API for loading configurations and features.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 2 +- .../hwtracing/coresight/coresight-config.h | 170 ++++++++++++ drivers/hwtracing/coresight/coresight-core.c | 12 +- .../hwtracing/coresight/coresight-etm-perf.c | 2 +- .../hwtracing/coresight/coresight-etm-perf.h | 2 +- .../hwtracing/coresight/coresight-syscfg.c | 247 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 57 ++++ 7 files changed, 488 insertions(+), 4 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-config.h create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.h
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index f20e357758d1..4ce854c434b1 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -4,7 +4,7 @@ # obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \
coresight-sysfs.o
coresight-sysfs.o coresight-syscfg.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h new file mode 100644 index 000000000000..0d9ae1dc4517 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -0,0 +1,170 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#ifndef _CORESIGHT_CORESIGHT_CONFIG_H +#define _CORESIGHT_CORESIGHT_CONFIG_H
+#include <linux/coresight.h> +#include <linux/types.h>
+/* CoreSight Configuration - complex component and system config handling */
+/* generic register flags */ +#define CS_CFG_REG_STD 0x80000000 /* reg is standard reg */ +#define CS_CFG_REG_RESOURCE 0x40000000 /* reg is a resource */ +#define CS_CFG_REG_VAL_PARAM 0x08000000 /* reg value uses param */ +#define CS_CFG_REG_VAL_MASK 0x04000000 /* reg value bit masked */ +#define CS_CFG_REG_VAL_64BIT 0x02000000 /* reg value 64 bit */ +#define CS_CFG_REG_VAL_SAVE 0x01000000 /* reg value save on disable */ +#define CS_CFG_REG_ID_MASK 0x00000FFF /* reg offset / id in device */ +#define CS_CFG_REG_DEV_MASK 0x00FFF000 /* device specific flags */
+/*
- flags defining what device class a feature will match to when processing a
- system configuration - used by config data and devices.
- */
+#define CS_CFG_MATCH_CLASS_SRC_ALL 0x0001 /* match any source */ +#define CS_CFG_MATCH_CLASS_SRC_ETM4 0x0002 /* match any ETMv4 device */ +#define CS_CFG_MATCH_CLASS_CTI_ALL 0x0004 /* match any CTI device */ +#define CS_CFG_MATCH_CLASS_CTI_CPU 0x0008 +#define CS_CFG_MATCH_CLASS_CTI_SYS 0x0010
+/* flags defining device instance matching - used in config data. */ +#define CS_CFG_MATCH_INST_ANY 0x80000000 /* any instance of a class */ +#define CS_CFG_MATCH_INST_AMBA_DEVICE 0x40000000 /* specific amba device */
+/*
- Limit number of presets in a configuration
- This is related to the number of bits (4) we use to select the preset on
- the perf command line. Preset 0 is always none selected.
- See PMU_FORMAT_ATTR(preset, "config:0-3") in coresight-etm-perf.c
- */
+#define CS_CFG_CONFIG_PRESET_MAX 15
+/**
- Parameter descriptor for a device feature.
- @name: Name of parameter.
- @value: Initial or default value.
- */
+struct cscfg_parameter_desc {
- const char *name;
- u64 value;
+};
+/**
- Representation of register value.
- Supports full 64 bit register value, or 32 bit value with optional mask
- value.
- @flags: define value usage as 32bit, 32bit+mask or 64bit.
- @val64: 64 bit value.
- @val32: 32 bit value.
- @mask32: 32 bit mask when using 32 bit value to access device register.
- */
+struct cscfg_regval {
- u32 flags;
- union {
u64 val64;
struct {
u32 val32;
u32 mask32;
};
- };
+};
+/**
- Device feature descriptor - combination of registers and parameters to
- program a device to implement a specific complex function.
- @name: feature name.
- @brief: brief description of the feature.
- @item: List entry.
- @match_flags: matching information if loading into a device
- @nr_params: number of parameters used.
- @params: array of parameters used.
- @nr_regs: number of registers used.
- @reg: array of registers used.
- */
+struct cscfg_feature_desc {
- const char *name;
- const char *brief;
- struct list_head item;
- u32 match_flags;
- int nr_params;
- struct cscfg_parameter_desc *params;
- int nr_regs;
- struct cscfg_regval *regs;
+};
+/**
- Device / feature matching information.
- Used by loading configurations to define which class or specific devices
- they want to match used features to, and registered devices to specify which
- matching class and information they support.
- The load process uses these matching pairs to load feature instances into
- matching devices.
- @match_flags: used to match to a particular class of device.
- @dev_name: used to match to a particular device instance on the system.
- */
+struct cscfg_match_info {
- u32 match_flags;
- /* unique device name (e.g. amba bus name) for specific device match */
- const char *dev_name;
+};
+/**
- Descriptor for features referenced by a configuration.
- @name: name of feature to use. Match against the @name in struct
cscfg_feature_desc.
- @nr_params: number of parameters the feature has.
- @match: match info for the feature when used in this configuration -
may be all devices of a class or a specific device in that class.
- */
+struct cscfg_config_feat_ref {
- const char *name;
- int nr_params;
- struct cscfg_match_info match;
+};
+/**
- Configuration descriptor - describes selectable system configuration.
- A configuration describes device features in use, and may provide preset
- values for the parameters in those features.
- A single set of presets is the sum of the parameters declared by
- all the features in use - this value is @nr_total_params.
- @name: name of the configuration - used for selection.
- @brief: description of the purpose of the configuration.
- @item: list entry.
- @nr_refs: Number of features used in this configuration.
- @refs: references to features used in this configuration..
- @nr_presets: Number of sets of presets supplied by this configuration.
- @nr_total_params: Sum of all parameters declared by used features
- @presets: Array of preset values.
- */
+struct cscfg_config_desc {
- const char *name;
- const char *brief;
- struct list_head item;
- int nr_refs;
- struct cscfg_config_feat_ref *refs;
- int nr_presets;
- int nr_total_params;
- const u64 *presets; /* nr_presets * nr_total_params */
+};
+#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 29c83eac3106..481d2b7b6b6f 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -21,6 +21,7 @@ #include "coresight-etm-perf.h" #include "coresight-priv.h" +#include "coresight-syscfg.h" static DEFINE_MUTEX(coresight_mutex); @@ -1675,13 +1676,22 @@ static int __init coresight_init(void) ret = etm_perf_init(); if (ret)
bus_unregister(&coresight_bustype);
goto exit_bus_unregister;
- /* initialise the coresight syscfg API */
- ret = cscfg_init();
- if (!ret)
return 0;
- etm_perf_exit();
+exit_bus_unregister:
- bus_unregister(&coresight_bustype); return ret;
} static void __exit coresight_exit(void) {
- cscfg_exit(); etm_perf_exit(); bus_unregister(&coresight_bustype);
} diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index bdc34ca449f7..a608081bd446 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -627,7 +627,7 @@ int __init etm_perf_init(void) return ret; } -void __exit etm_perf_exit(void) +void etm_perf_exit(void) { perf_pmu_unregister(&etm_pmu); } diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.h b/drivers/hwtracing/coresight/coresight-etm-perf.h index 3e4f2ad5e193..29d90dfeba31 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.h +++ b/drivers/hwtracing/coresight/coresight-etm-perf.h @@ -83,6 +83,6 @@ static inline void *etm_perf_sink_config(struct perf_output_handle *handle) #endif /* CONFIG_CORESIGHT */ int __init etm_perf_init(void); -void __exit etm_perf_exit(void); +void etm_perf_exit(void); #endif diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c new file mode 100644 index 000000000000..6f89541af7a0 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <linux/platform_device.h>
+#include "coresight-config.h" +#include "coresight-syscfg.h"
+/*
- cscfg_ API manages configurations and features for the entire coresight
- infrastructure.
- It allows the loading of configurations and features, and loads these into
- coresight devices as appropriate.
- */
+static DEFINE_MUTEX(cscfg_mutex);
+/* only one of these */ +static struct cscfg_api_data cscfg_data;
+/* get reference to cscfg device */ +struct device *to_device_cscfg(void);
+/* load features and configuations into the lists */
+/* check feature list for a named feature - call with mutex locked. */ +static bool cscfg_match_list_feat(const char *name) +{
- struct cscfg_feature_desc *curr_item;
- list_for_each_entry(curr_item, &cscfg_data.feat_list, item) {
if (strcmp(curr_item->name, name) == 0)
return true;
- }
- return false;
+}
+/* check all feat needed for cfg are in the list - call with mutex locked. */ +static int cscfg_check_feat_for_cfg(struct cscfg_config_desc *cfg_desc) +{
- int i;
- for (i = 0; i < cfg_desc->nr_refs; i++)
if (!cscfg_match_list_feat(cfg_desc->refs[i].name))
return -EINVAL;
- return 0;
+}
+/*
- load feature - add to feature list.
- */
+static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc) +{
- list_add(&feat_desc->item, &cscfg_data.feat_list);
- return 0;
+}
+/*
- load config into the system - validate used features exist then add to
- config list.
- */
+static int cscfg_load_config(struct cscfg_config_desc *cfg_desc) +{
- int err;
- /* validate features are present */
- err = cscfg_check_feat_for_cfg(cfg_desc);
- if (err)
return err;
- list_add(&cfg_desc->item, &cscfg_data.config_list);
- return 0;
+}
+/*
- External API function to load feature and config sets.
- Take a 0 terminated array of feature descriptors and/or configuration
- descriptors and load into the system.
- Features are loaded first to ensure configuration dependencies can be met.
- */
+int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs,
struct cscfg_feature_desc **feat_descs)
+{
- int err, i = 0;
- mutex_lock(&cscfg_mutex);
- /* load features first */
- if (feat_descs) {
while (feat_descs[i]) {
err = cscfg_load_feat(feat_descs[i]);
if (err) {
pr_err("coresight-syscfg: Failed to load feature %s\n",
feat_descs[i]->name);
goto do_unlock;
}
i++;
}
- }
- /* next any configurations to check feature dependencies */
- i = 0;
- if (cfg_descs) {
while (cfg_descs[i]) {
err = cscfg_load_config(cfg_descs[i]);
if (err) {
pr_err("coresight-syscfg: Failed to load configuration %s\n",
cfg_descs[i]->name);
goto do_unlock;
}
i++;
}
- }
+do_unlock:
- mutex_unlock(&cscfg_mutex);
- return err;
+} +EXPORT_SYMBOL_GPL(cscfg_load_config_sets);
+/* Initialise system configuration management driver. */ +/* only one of these */ +static struct cscfg_device *cscfg_dev;
+/*
- We have a separate coresight-config bus for the config device so it does
- not appear on the main coresight bus and affect device searches on that bus.
- */
+static struct bus_type cscfg_bus_type = {
- .name = "coresight-config",
+};
+struct device *to_device_cscfg(void) +{
- return cscfg_dev ? &cscfg_dev->dev : NULL;
+}
+/* Must have a release function or the kernel will complain on module unload */ +void cscfg_dev_release(struct device *dev) +{
- kfree(cscfg_dev);
- cscfg_dev = NULL;
+}
+int cscfg_create_device(void) +{
- struct device *dev;
- int err = -ENOMEM;
- mutex_lock(&cscfg_mutex);
- if (cscfg_dev) {
err = -EINVAL;
goto create_dev_exit_unlock;
- }
- cscfg_dev = kzalloc(sizeof(struct cscfg_device), GFP_KERNEL);
- if (!cscfg_dev)
goto create_dev_exit_unlock;
- /* setup the device */
- dev = to_device_cscfg();
- dev->bus = &cscfg_bus_type;
- dev->parent = &platform_bus;
- dev->release = cscfg_dev_release;
- dev->init_name = "system_cfg";
- cscfg_dev->cfg_data = &cscfg_data;
- err = device_register(dev);
- if (err)
cscfg_dev_release(dev);
+create_dev_exit_unlock:
- mutex_unlock(&cscfg_mutex);
- return err;
+}
+void cscfg_clear_device(void) +{
- mutex_lock(&cscfg_mutex);
- device_unregister(to_device_cscfg());
- mutex_unlock(&cscfg_mutex);
+}
+/* driver initialisation */ +static struct cscfg_driver cs_config_driver = {
- .drv = {
.name = "cs-syscfg-drv",
.owner = THIS_MODULE,
.suppress_bind_attrs = true,
- },
+};
+int __init cscfg_driver_init(void) +{
- cs_config_driver.drv.bus = &cscfg_bus_type;
- return driver_register(&cs_config_driver.drv);
+}
+void cscfg_driver_exit(void) +{
- driver_unregister(&cs_config_driver.drv);
+}
+/* Initialise system config management API */ +int __init cscfg_init(void) +{
- int err = 0;
- err = bus_register(&cscfg_bus_type);
- if (err)
return err;
- err = cscfg_driver_init();
- if (err)
goto exit_bus_unregister;
- err = cscfg_create_device();
- if (err)
goto exit_drv_unregister;
- INIT_LIST_HEAD(&cscfg_data.dev_list);
- INIT_LIST_HEAD(&cscfg_data.feat_list);
- INIT_LIST_HEAD(&cscfg_data.config_list);
- cscfg_data.nr_csdev = 0;
- dev_info(to_device_cscfg(), "CoreSight Configuration manager initialised");
- return 0;
+exit_drv_unregister:
- cscfg_driver_exit();
+exit_bus_unregister:
- bus_unregister(&cscfg_bus_type);
- return err;
+}
+void __exit cscfg_exit(void) +{
- cscfg_clear_device();
- cscfg_driver_exit();
- bus_unregister(&cscfg_bus_type);
+} diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h new file mode 100644 index 000000000000..5a7896426eab --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/*
- Coresight system configuration driver.
- */
+#ifndef CORESIGHT_SYSCFG_H +#define CORESIGHT_SYSCFG_H
+#include <linux/coresight.h> +#include <linux/device.h>
+#include "coresight-config.h"
+/**
- System configuration API data.
- @dev_list: List of other coresight devices registered with this device.
- @feat_list: List of features to load into registered devices.
- @config_list:List of system configurations to load into registered devices.
- @nr_csdev: Number of registered devices with the cscfg system
- */
+struct cscfg_api_data {
- struct list_head dev_list;
struct list_head csdev_desc_list;
And I would rename cscfg_csdev_register to cscfg_csdev_desc in patch 02.
- struct list_head feat_list;
struct list_head feat_desc_list;
- struct list_head config_list;
struct list_head config_desc_list;
That way we know exactly what is enqued.
- int nr_csdev;
+};
+/* internal core operations for cscfg */ +int __init cscfg_init(void); +void __exit cscfg_exit(void);
+/* syscfg external API */ +int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs,
struct cscfg_feature_desc **feat_descs);
+/* system configuration device driver and API */ +/**
- System configuration device.
- Need a device to 'own' some coresight system wide sysfs entries in
- perf events etc.
- @dev: The device.
- @cfg_data: A reference to the configuration and feature lists
- */
+struct cscfg_device {
- struct device dev;
- struct cscfg_api_data *cfg_data;
+};
+/* basic device driver */ +struct cscfg_driver {
- struct device_driver drv;
+};
+#endif /* CORESIGHT_SYSCFG_H */
2.17.1
On Fri, Oct 30, 2020 at 05:56:47PM +0000, Mike Leach wrote:
Creates an system management API to allow complex configurations and features to be programmed into a CoreSight infrastructure.
A feature is defined as a programming set for a device or class of devices.
A configuration is a set of features across the system that are enabled for a trace session.
The API will manage system wide configuration, and allow complex programmed features to be added to individual device instances, and provide for system wide configuration selection on trace capture operations.
This patch creates the initial data object and the initial API for loading configurations and features.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 2 +- .../hwtracing/coresight/coresight-config.h | 170 ++++++++++++ drivers/hwtracing/coresight/coresight-core.c | 12 +- .../hwtracing/coresight/coresight-etm-perf.c | 2 +- .../hwtracing/coresight/coresight-etm-perf.h | 2 +- .../hwtracing/coresight/coresight-syscfg.c | 247 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 57 ++++ 7 files changed, 488 insertions(+), 4 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-config.h create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.h
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index f20e357758d1..4ce854c434b1 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -4,7 +4,7 @@ # obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \
coresight-sysfs.o
coresight-sysfs.o coresight-syscfg.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h new file mode 100644 index 000000000000..0d9ae1dc4517 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -0,0 +1,170 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#ifndef _CORESIGHT_CORESIGHT_CONFIG_H +#define _CORESIGHT_CORESIGHT_CONFIG_H
+#include <linux/coresight.h> +#include <linux/types.h>
+/* CoreSight Configuration - complex component and system config handling */
+/* generic register flags */ +#define CS_CFG_REG_STD 0x80000000 /* reg is standard reg */ +#define CS_CFG_REG_RESOURCE 0x40000000 /* reg is a resource */ +#define CS_CFG_REG_VAL_PARAM 0x08000000 /* reg value uses param */ +#define CS_CFG_REG_VAL_MASK 0x04000000 /* reg value bit masked */ +#define CS_CFG_REG_VAL_64BIT 0x02000000 /* reg value 64 bit */ +#define CS_CFG_REG_VAL_SAVE 0x01000000 /* reg value save on disable */ +#define CS_CFG_REG_ID_MASK 0x00000FFF /* reg offset / id in device */ +#define CS_CFG_REG_DEV_MASK 0x00FFF000 /* device specific flags */
+/*
- flags defining what device class a feature will match to when processing a
- system configuration - used by config data and devices.
- */
+#define CS_CFG_MATCH_CLASS_SRC_ALL 0x0001 /* match any source */ +#define CS_CFG_MATCH_CLASS_SRC_ETM4 0x0002 /* match any ETMv4 device */ +#define CS_CFG_MATCH_CLASS_CTI_ALL 0x0004 /* match any CTI device */ +#define CS_CFG_MATCH_CLASS_CTI_CPU 0x0008 +#define CS_CFG_MATCH_CLASS_CTI_SYS 0x0010
+/* flags defining device instance matching - used in config data. */ +#define CS_CFG_MATCH_INST_ANY 0x80000000 /* any instance of a class */ +#define CS_CFG_MATCH_INST_AMBA_DEVICE 0x40000000 /* specific amba device */
+/*
- Limit number of presets in a configuration
- This is related to the number of bits (4) we use to select the preset on
- the perf command line. Preset 0 is always none selected.
- See PMU_FORMAT_ATTR(preset, "config:0-3") in coresight-etm-perf.c
- */
+#define CS_CFG_CONFIG_PRESET_MAX 15
+/**
- Parameter descriptor for a device feature.
- @name: Name of parameter.
- @value: Initial or default value.
- */
+struct cscfg_parameter_desc {
- const char *name;
- u64 value;
+};
+/**
- Representation of register value.
- Supports full 64 bit register value, or 32 bit value with optional mask
- value.
- @flags: define value usage as 32bit, 32bit+mask or 64bit.
- @val64: 64 bit value.
- @val32: 32 bit value.
- @mask32: 32 bit mask when using 32 bit value to access device register.
- */
+struct cscfg_regval {
- u32 flags;
- union {
u64 val64;
struct {
u32 val32;
u32 mask32;
};
- };
+};
+/**
- Device feature descriptor - combination of registers and parameters to
- program a device to implement a specific complex function.
- @name: feature name.
- @brief: brief description of the feature.
- @item: List entry.
- @match_flags: matching information if loading into a device
- @nr_params: number of parameters used.
- @params: array of parameters used.
- @nr_regs: number of registers used.
- @reg: array of registers used.
- */
+struct cscfg_feature_desc {
- const char *name;
- const char *brief;
- struct list_head item;
- u32 match_flags;
- int nr_params;
- struct cscfg_parameter_desc *params;
- int nr_regs;
- struct cscfg_regval *regs;
+};
+/**
- Device / feature matching information.
- Used by loading configurations to define which class or specific devices
- they want to match used features to, and registered devices to specify which
- matching class and information they support.
- The load process uses these matching pairs to load feature instances into
- matching devices.
- @match_flags: used to match to a particular class of device.
- @dev_name: used to match to a particular device instance on the system.
- */
+struct cscfg_match_info {
- u32 match_flags;
- /* unique device name (e.g. amba bus name) for specific device match */
- const char *dev_name;
+};
+/**
- Descriptor for features referenced by a configuration.
- @name: name of feature to use. Match against the @name in struct
cscfg_feature_desc.
- @nr_params: number of parameters the feature has.
- @match: match info for the feature when used in this configuration -
may be all devices of a class or a specific device in that class.
- */
+struct cscfg_config_feat_ref {
- const char *name;
- int nr_params;
- struct cscfg_match_info match;
+};
+/**
- Configuration descriptor - describes selectable system configuration.
- A configuration describes device features in use, and may provide preset
- values for the parameters in those features.
- A single set of presets is the sum of the parameters declared by
- all the features in use - this value is @nr_total_params.
- @name: name of the configuration - used for selection.
- @brief: description of the purpose of the configuration.
- @item: list entry.
- @nr_refs: Number of features used in this configuration.
- @refs: references to features used in this configuration..
- @nr_presets: Number of sets of presets supplied by this configuration.
- @nr_total_params: Sum of all parameters declared by used features
- @presets: Array of preset values.
- */
+struct cscfg_config_desc {
- const char *name;
- const char *brief;
- struct list_head item;
- int nr_refs;
- struct cscfg_config_feat_ref *refs;
- int nr_presets;
- int nr_total_params;
- const u64 *presets; /* nr_presets * nr_total_params */
+};
+#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 29c83eac3106..481d2b7b6b6f 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -21,6 +21,7 @@ #include "coresight-etm-perf.h" #include "coresight-priv.h" +#include "coresight-syscfg.h" static DEFINE_MUTEX(coresight_mutex); @@ -1675,13 +1676,22 @@ static int __init coresight_init(void) ret = etm_perf_init(); if (ret)
bus_unregister(&coresight_bustype);
goto exit_bus_unregister;
- /* initialise the coresight syscfg API */
- ret = cscfg_init();
- if (!ret)
return 0;
- etm_perf_exit();
+exit_bus_unregister:
- bus_unregister(&coresight_bustype); return ret;
} static void __exit coresight_exit(void) {
- cscfg_exit(); etm_perf_exit(); bus_unregister(&coresight_bustype);
} diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index bdc34ca449f7..a608081bd446 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -627,7 +627,7 @@ int __init etm_perf_init(void) return ret; } -void __exit etm_perf_exit(void) +void etm_perf_exit(void) { perf_pmu_unregister(&etm_pmu); } diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.h b/drivers/hwtracing/coresight/coresight-etm-perf.h index 3e4f2ad5e193..29d90dfeba31 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.h +++ b/drivers/hwtracing/coresight/coresight-etm-perf.h @@ -83,6 +83,6 @@ static inline void *etm_perf_sink_config(struct perf_output_handle *handle) #endif /* CONFIG_CORESIGHT */ int __init etm_perf_init(void); -void __exit etm_perf_exit(void); +void etm_perf_exit(void); #endif diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c new file mode 100644 index 000000000000..6f89541af7a0 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <linux/platform_device.h>
+#include "coresight-config.h" +#include "coresight-syscfg.h"
+/*
- cscfg_ API manages configurations and features for the entire coresight
- infrastructure.
- It allows the loading of configurations and features, and loads these into
- coresight devices as appropriate.
- */
+static DEFINE_MUTEX(cscfg_mutex);
+/* only one of these */ +static struct cscfg_api_data cscfg_data;
+/* get reference to cscfg device */ +struct device *to_device_cscfg(void);
+/* load features and configuations into the lists */
+/* check feature list for a named feature - call with mutex locked. */ +static bool cscfg_match_list_feat(const char *name) +{
- struct cscfg_feature_desc *curr_item;
- list_for_each_entry(curr_item, &cscfg_data.feat_list, item) {
if (strcmp(curr_item->name, name) == 0)
return true;
- }
- return false;
+}
+/* check all feat needed for cfg are in the list - call with mutex locked. */ +static int cscfg_check_feat_for_cfg(struct cscfg_config_desc *cfg_desc) +{
- int i;
- for (i = 0; i < cfg_desc->nr_refs; i++)
if (!cscfg_match_list_feat(cfg_desc->refs[i].name))
return -EINVAL;
- return 0;
+}
+/*
- load feature - add to feature list.
- */
+static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc) +{
- list_add(&feat_desc->item, &cscfg_data.feat_list);
- return 0;
+}
+/*
- load config into the system - validate used features exist then add to
- config list.
- */
+static int cscfg_load_config(struct cscfg_config_desc *cfg_desc) +{
- int err;
- /* validate features are present */
- err = cscfg_check_feat_for_cfg(cfg_desc);
- if (err)
return err;
- list_add(&cfg_desc->item, &cscfg_data.config_list);
- return 0;
+}
+/*
- External API function to load feature and config sets.
- Take a 0 terminated array of feature descriptors and/or configuration
- descriptors and load into the system.
- Features are loaded first to ensure configuration dependencies can be met.
- */
+int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs,
struct cscfg_feature_desc **feat_descs)
+{
- int err, i = 0;
- mutex_lock(&cscfg_mutex);
- /* load features first */
- if (feat_descs) {
while (feat_descs[i]) {
err = cscfg_load_feat(feat_descs[i]);
if (err) {
pr_err("coresight-syscfg: Failed to load feature %s\n",
feat_descs[i]->name);
goto do_unlock;
}
i++;
}
- }
- /* next any configurations to check feature dependencies */
- i = 0;
- if (cfg_descs) {
while (cfg_descs[i]) {
err = cscfg_load_config(cfg_descs[i]);
if (err) {
pr_err("coresight-syscfg: Failed to load configuration %s\n",
cfg_descs[i]->name);
goto do_unlock;
}
i++;
}
- }
+do_unlock:
- mutex_unlock(&cscfg_mutex);
- return err;
+} +EXPORT_SYMBOL_GPL(cscfg_load_config_sets);
+/* Initialise system configuration management driver. */ +/* only one of these */ +static struct cscfg_device *cscfg_dev;
+/*
- We have a separate coresight-config bus for the config device so it does
- not appear on the main coresight bus and affect device searches on that bus.
- */
+static struct bus_type cscfg_bus_type = {
- .name = "coresight-config",
+};
+struct device *to_device_cscfg(void) +{
- return cscfg_dev ? &cscfg_dev->dev : NULL;
+}
+/* Must have a release function or the kernel will complain on module unload */ +void cscfg_dev_release(struct device *dev) +{
- kfree(cscfg_dev);
- cscfg_dev = NULL;
+}
+int cscfg_create_device(void) +{
- struct device *dev;
- int err = -ENOMEM;
- mutex_lock(&cscfg_mutex);
- if (cscfg_dev) {
err = -EINVAL;
goto create_dev_exit_unlock;
- }
- cscfg_dev = kzalloc(sizeof(struct cscfg_device), GFP_KERNEL);
- if (!cscfg_dev)
goto create_dev_exit_unlock;
- /* setup the device */
- dev = to_device_cscfg();
- dev->bus = &cscfg_bus_type;
- dev->parent = &platform_bus;
cscfg_dev.dev doesn't have to be on a bus, nor does it need to have the platform_bus as a parent.
- dev->release = cscfg_dev_release;
- dev->init_name = "system_cfg";
- cscfg_dev->cfg_data = &cscfg_data;
- err = device_register(dev);
- if (err)
cscfg_dev_release(dev);
+create_dev_exit_unlock:
- mutex_unlock(&cscfg_mutex);
- return err;
+}
+void cscfg_clear_device(void) +{
- mutex_lock(&cscfg_mutex);
- device_unregister(to_device_cscfg());
- mutex_unlock(&cscfg_mutex);
+}
+/* driver initialisation */ +static struct cscfg_driver cs_config_driver = {
- .drv = {
.name = "cs-syscfg-drv",
.owner = THIS_MODULE,
.suppress_bind_attrs = true,
- },
+};
+int __init cscfg_driver_init(void) +{
- cs_config_driver.drv.bus = &cscfg_bus_type;
- return driver_register(&cs_config_driver.drv);
+}
As far as I can tell no device is using the cs_config_driver. I'm also don't understand the scenario where seeing the system_cfg device under the coresight-config bus is useful for users. More on that front below.
+void cscfg_driver_exit(void) +{
- driver_unregister(&cs_config_driver.drv);
+}
+/* Initialise system config management API */ +int __init cscfg_init(void) +{
- int err = 0;
- err = bus_register(&cscfg_bus_type);
- if (err)
return err;
- err = cscfg_driver_init();
- if (err)
goto exit_bus_unregister;
Convinced I was missing something big I applied all the patches in this set and commented out the bus_register() and cscfg_driver_init() above. I also commented out dev->bus and dev->parent in cscfg_create_device(). Everything compiled and I couldn't find a difference in terms of functionality.
To me the configuration manager should be a library available to the rest of the coresight framework. In fact after removing the above that is exactly what it becomes.
- err = cscfg_create_device();
- if (err)
goto exit_drv_unregister;
- INIT_LIST_HEAD(&cscfg_data.dev_list);
- INIT_LIST_HEAD(&cscfg_data.feat_list);
- INIT_LIST_HEAD(&cscfg_data.config_list);
- cscfg_data.nr_csdev = 0;
- dev_info(to_device_cscfg(), "CoreSight Configuration manager initialised");
- return 0;
+exit_drv_unregister:
- cscfg_driver_exit();
+exit_bus_unregister:
- bus_unregister(&cscfg_bus_type);
- return err;
+}
+void __exit cscfg_exit(void) +{
- cscfg_clear_device();
- cscfg_driver_exit();
- bus_unregister(&cscfg_bus_type);
+} diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h new file mode 100644 index 000000000000..5a7896426eab --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/*
- Coresight system configuration driver.
- */
+#ifndef CORESIGHT_SYSCFG_H +#define CORESIGHT_SYSCFG_H
+#include <linux/coresight.h> +#include <linux/device.h>
+#include "coresight-config.h"
+/**
- System configuration API data.
- @dev_list: List of other coresight devices registered with this device.
- @feat_list: List of features to load into registered devices.
- @config_list:List of system configurations to load into registered devices.
- @nr_csdev: Number of registered devices with the cscfg system
- */
+struct cscfg_api_data {
- struct list_head dev_list;
- struct list_head feat_list;
- struct list_head config_list;
- int nr_csdev;
+};
+/* internal core operations for cscfg */ +int __init cscfg_init(void); +void __exit cscfg_exit(void);
+/* syscfg external API */ +int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs,
struct cscfg_feature_desc **feat_descs);
+/* system configuration device driver and API */ +/**
- System configuration device.
- Need a device to 'own' some coresight system wide sysfs entries in
- perf events etc.
- @dev: The device.
- @cfg_data: A reference to the configuration and feature lists
- */
+struct cscfg_device {
- struct device dev;
- struct cscfg_api_data *cfg_data;
+};
+/* basic device driver */ +struct cscfg_driver {
- struct device_driver drv;
+};
+#endif /* CORESIGHT_SYSCFG_H */
2.17.1
HI Mathieu,
Followed pretty much all of your suggestions here - and in prior comments on this patch.
On Thu, 26 Nov 2020 at 18:35, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Fri, Oct 30, 2020 at 05:56:47PM +0000, Mike Leach wrote:
Creates an system management API to allow complex configurations and features to be programmed into a CoreSight infrastructure.
A feature is defined as a programming set for a device or class of devices.
A configuration is a set of features across the system that are enabled for a trace session.
The API will manage system wide configuration, and allow complex programmed features to be added to individual device instances, and provide for system wide configuration selection on trace capture operations.
This patch creates the initial data object and the initial API for loading configurations and features.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 2 +- .../hwtracing/coresight/coresight-config.h | 170 ++++++++++++ drivers/hwtracing/coresight/coresight-core.c | 12 +- .../hwtracing/coresight/coresight-etm-perf.c | 2 +- .../hwtracing/coresight/coresight-etm-perf.h | 2 +- .../hwtracing/coresight/coresight-syscfg.c | 247 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 57 ++++ 7 files changed, 488 insertions(+), 4 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-config.h create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.h
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index f20e357758d1..4ce854c434b1 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -4,7 +4,7 @@ # obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \
coresight-sysfs.o
coresight-sysfs.o coresight-syscfg.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h new file mode 100644 index 000000000000..0d9ae1dc4517 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -0,0 +1,170 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#ifndef _CORESIGHT_CORESIGHT_CONFIG_H +#define _CORESIGHT_CORESIGHT_CONFIG_H
+#include <linux/coresight.h> +#include <linux/types.h>
+/* CoreSight Configuration - complex component and system config handling */
+/* generic register flags */ +#define CS_CFG_REG_STD 0x80000000 /* reg is standard reg */ +#define CS_CFG_REG_RESOURCE 0x40000000 /* reg is a resource */ +#define CS_CFG_REG_VAL_PARAM 0x08000000 /* reg value uses param */ +#define CS_CFG_REG_VAL_MASK 0x04000000 /* reg value bit masked */ +#define CS_CFG_REG_VAL_64BIT 0x02000000 /* reg value 64 bit */ +#define CS_CFG_REG_VAL_SAVE 0x01000000 /* reg value save on disable */ +#define CS_CFG_REG_ID_MASK 0x00000FFF /* reg offset / id in device */ +#define CS_CFG_REG_DEV_MASK 0x00FFF000 /* device specific flags */
+/*
- flags defining what device class a feature will match to when processing a
- system configuration - used by config data and devices.
- */
+#define CS_CFG_MATCH_CLASS_SRC_ALL 0x0001 /* match any source */ +#define CS_CFG_MATCH_CLASS_SRC_ETM4 0x0002 /* match any ETMv4 device */ +#define CS_CFG_MATCH_CLASS_CTI_ALL 0x0004 /* match any CTI device */ +#define CS_CFG_MATCH_CLASS_CTI_CPU 0x0008 +#define CS_CFG_MATCH_CLASS_CTI_SYS 0x0010
+/* flags defining device instance matching - used in config data. */ +#define CS_CFG_MATCH_INST_ANY 0x80000000 /* any instance of a class */ +#define CS_CFG_MATCH_INST_AMBA_DEVICE 0x40000000 /* specific amba device */
+/*
- Limit number of presets in a configuration
- This is related to the number of bits (4) we use to select the preset on
- the perf command line. Preset 0 is always none selected.
- See PMU_FORMAT_ATTR(preset, "config:0-3") in coresight-etm-perf.c
- */
+#define CS_CFG_CONFIG_PRESET_MAX 15
+/**
- Parameter descriptor for a device feature.
- @name: Name of parameter.
- @value: Initial or default value.
- */
+struct cscfg_parameter_desc {
const char *name;
u64 value;
+};
+/**
- Representation of register value.
- Supports full 64 bit register value, or 32 bit value with optional mask
- value.
- @flags: define value usage as 32bit, 32bit+mask or 64bit.
- @val64: 64 bit value.
- @val32: 32 bit value.
- @mask32: 32 bit mask when using 32 bit value to access device register.
- */
+struct cscfg_regval {
u32 flags;
union {
u64 val64;
struct {
u32 val32;
u32 mask32;
};
};
+};
+/**
- Device feature descriptor - combination of registers and parameters to
- program a device to implement a specific complex function.
- @name: feature name.
- @brief: brief description of the feature.
- @item: List entry.
- @match_flags: matching information if loading into a device
- @nr_params: number of parameters used.
- @params: array of parameters used.
- @nr_regs: number of registers used.
- @reg: array of registers used.
- */
+struct cscfg_feature_desc {
const char *name;
const char *brief;
struct list_head item;
u32 match_flags;
int nr_params;
struct cscfg_parameter_desc *params;
int nr_regs;
struct cscfg_regval *regs;
+};
+/**
- Device / feature matching information.
- Used by loading configurations to define which class or specific devices
- they want to match used features to, and registered devices to specify which
- matching class and information they support.
- The load process uses these matching pairs to load feature instances into
- matching devices.
- @match_flags: used to match to a particular class of device.
- @dev_name: used to match to a particular device instance on the system.
- */
+struct cscfg_match_info {
u32 match_flags;
/* unique device name (e.g. amba bus name) for specific device match */
const char *dev_name;
+};
+/**
- Descriptor for features referenced by a configuration.
- @name: name of feature to use. Match against the @name in struct
cscfg_feature_desc.
- @nr_params: number of parameters the feature has.
- @match: match info for the feature when used in this configuration -
may be all devices of a class or a specific device in that class.
- */
+struct cscfg_config_feat_ref {
const char *name;
int nr_params;
struct cscfg_match_info match;
+};
+/**
- Configuration descriptor - describes selectable system configuration.
- A configuration describes device features in use, and may provide preset
- values for the parameters in those features.
- A single set of presets is the sum of the parameters declared by
- all the features in use - this value is @nr_total_params.
- @name: name of the configuration - used for selection.
- @brief: description of the purpose of the configuration.
- @item: list entry.
- @nr_refs: Number of features used in this configuration.
- @refs: references to features used in this configuration..
- @nr_presets: Number of sets of presets supplied by this configuration.
- @nr_total_params: Sum of all parameters declared by used features
- @presets: Array of preset values.
- */
+struct cscfg_config_desc {
const char *name;
const char *brief;
struct list_head item;
int nr_refs;
struct cscfg_config_feat_ref *refs;
int nr_presets;
int nr_total_params;
const u64 *presets; /* nr_presets * nr_total_params */
+};
+#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 29c83eac3106..481d2b7b6b6f 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -21,6 +21,7 @@
#include "coresight-etm-perf.h" #include "coresight-priv.h" +#include "coresight-syscfg.h"
static DEFINE_MUTEX(coresight_mutex);
@@ -1675,13 +1676,22 @@ static int __init coresight_init(void)
ret = etm_perf_init(); if (ret)
bus_unregister(&coresight_bustype);
goto exit_bus_unregister;
/* initialise the coresight syscfg API */
ret = cscfg_init();
if (!ret)
return 0;
etm_perf_exit();
+exit_bus_unregister:
bus_unregister(&coresight_bustype); return ret;
}
static void __exit coresight_exit(void) {
cscfg_exit(); etm_perf_exit(); bus_unregister(&coresight_bustype);
} diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index bdc34ca449f7..a608081bd446 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -627,7 +627,7 @@ int __init etm_perf_init(void) return ret; }
-void __exit etm_perf_exit(void) +void etm_perf_exit(void) { perf_pmu_unregister(&etm_pmu); } diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.h b/drivers/hwtracing/coresight/coresight-etm-perf.h index 3e4f2ad5e193..29d90dfeba31 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.h +++ b/drivers/hwtracing/coresight/coresight-etm-perf.h @@ -83,6 +83,6 @@ static inline void *etm_perf_sink_config(struct perf_output_handle *handle) #endif /* CONFIG_CORESIGHT */
int __init etm_perf_init(void); -void __exit etm_perf_exit(void); +void etm_perf_exit(void);
#endif diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c new file mode 100644 index 000000000000..6f89541af7a0 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <linux/platform_device.h>
+#include "coresight-config.h" +#include "coresight-syscfg.h"
+/*
- cscfg_ API manages configurations and features for the entire coresight
- infrastructure.
- It allows the loading of configurations and features, and loads these into
- coresight devices as appropriate.
- */
+static DEFINE_MUTEX(cscfg_mutex);
+/* only one of these */ +static struct cscfg_api_data cscfg_data;
+/* get reference to cscfg device */ +struct device *to_device_cscfg(void);
+/* load features and configuations into the lists */
+/* check feature list for a named feature - call with mutex locked. */ +static bool cscfg_match_list_feat(const char *name) +{
struct cscfg_feature_desc *curr_item;
list_for_each_entry(curr_item, &cscfg_data.feat_list, item) {
if (strcmp(curr_item->name, name) == 0)
return true;
}
return false;
+}
+/* check all feat needed for cfg are in the list - call with mutex locked. */ +static int cscfg_check_feat_for_cfg(struct cscfg_config_desc *cfg_desc) +{
int i;
for (i = 0; i < cfg_desc->nr_refs; i++)
if (!cscfg_match_list_feat(cfg_desc->refs[i].name))
return -EINVAL;
return 0;
+}
+/*
- load feature - add to feature list.
- */
+static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc) +{
list_add(&feat_desc->item, &cscfg_data.feat_list);
return 0;
+}
+/*
- load config into the system - validate used features exist then add to
- config list.
- */
+static int cscfg_load_config(struct cscfg_config_desc *cfg_desc) +{
int err;
/* validate features are present */
err = cscfg_check_feat_for_cfg(cfg_desc);
if (err)
return err;
list_add(&cfg_desc->item, &cscfg_data.config_list);
return 0;
+}
+/*
- External API function to load feature and config sets.
- Take a 0 terminated array of feature descriptors and/or configuration
- descriptors and load into the system.
- Features are loaded first to ensure configuration dependencies can be met.
- */
+int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs,
struct cscfg_feature_desc **feat_descs)
+{
int err, i = 0;
mutex_lock(&cscfg_mutex);
/* load features first */
if (feat_descs) {
while (feat_descs[i]) {
err = cscfg_load_feat(feat_descs[i]);
if (err) {
pr_err("coresight-syscfg: Failed to load feature %s\n",
feat_descs[i]->name);
goto do_unlock;
}
i++;
}
}
/* next any configurations to check feature dependencies */
i = 0;
if (cfg_descs) {
while (cfg_descs[i]) {
err = cscfg_load_config(cfg_descs[i]);
if (err) {
pr_err("coresight-syscfg: Failed to load configuration %s\n",
cfg_descs[i]->name);
goto do_unlock;
}
i++;
}
}
+do_unlock:
mutex_unlock(&cscfg_mutex);
return err;
+} +EXPORT_SYMBOL_GPL(cscfg_load_config_sets);
+/* Initialise system configuration management driver. */ +/* only one of these */ +static struct cscfg_device *cscfg_dev;
+/*
- We have a separate coresight-config bus for the config device so it does
- not appear on the main coresight bus and affect device searches on that bus.
- */
+static struct bus_type cscfg_bus_type = {
.name = "coresight-config",
+};
+struct device *to_device_cscfg(void) +{
return cscfg_dev ? &cscfg_dev->dev : NULL;
+}
+/* Must have a release function or the kernel will complain on module unload */ +void cscfg_dev_release(struct device *dev) +{
kfree(cscfg_dev);
cscfg_dev = NULL;
+}
+int cscfg_create_device(void) +{
struct device *dev;
int err = -ENOMEM;
mutex_lock(&cscfg_mutex);
if (cscfg_dev) {
err = -EINVAL;
goto create_dev_exit_unlock;
}
cscfg_dev = kzalloc(sizeof(struct cscfg_device), GFP_KERNEL);
if (!cscfg_dev)
goto create_dev_exit_unlock;
/* setup the device */
dev = to_device_cscfg();
dev->bus = &cscfg_bus_type;
dev->parent = &platform_bus;
cscfg_dev.dev doesn't have to be on a bus, nor does it need to have the platform_bus as a parent.
dev->release = cscfg_dev_release;
dev->init_name = "system_cfg";
cscfg_dev->cfg_data = &cscfg_data;
err = device_register(dev);
if (err)
cscfg_dev_release(dev);
+create_dev_exit_unlock:
mutex_unlock(&cscfg_mutex);
return err;
+}
+void cscfg_clear_device(void) +{
mutex_lock(&cscfg_mutex);
device_unregister(to_device_cscfg());
mutex_unlock(&cscfg_mutex);
+}
+/* driver initialisation */ +static struct cscfg_driver cs_config_driver = {
.drv = {
.name = "cs-syscfg-drv",
.owner = THIS_MODULE,
.suppress_bind_attrs = true,
},
+};
+int __init cscfg_driver_init(void) +{
cs_config_driver.drv.bus = &cscfg_bus_type;
return driver_register(&cs_config_driver.drv);
+}
As far as I can tell no device is using the cs_config_driver. I'm also don't understand the scenario where seeing the system_cfg device under the coresight-config bus is useful for users. More on that front below.
Probably isn't - was initially useful for me debugging - but not now.
+void cscfg_driver_exit(void) +{
driver_unregister(&cs_config_driver.drv);
+}
+/* Initialise system config management API */ +int __init cscfg_init(void) +{
int err = 0;
err = bus_register(&cscfg_bus_type);
if (err)
return err;
err = cscfg_driver_init();
if (err)
goto exit_bus_unregister;
Convinced I was missing something big I applied all the patches in this set and commented out the bus_register() and cscfg_driver_init() above. I also commented out dev->bus and dev->parent in cscfg_create_device(). Everything compiled and I couldn't find a difference in terms of functionality.
To me the configuration manager should be a library available to the rest of the coresight framework. In fact after removing the above that is exactly what it becomes.
Agreed. The device is there to "own" certain kernel elements such as the sysfs entries in the perf handling in the later patches of this set, but no need for bus ./ driver. The only reason they were there was the fact I assumed they needed to be based on the rest of the driver structures - I couldn't find a concrete example of a virtual device existing in isolation. however, it works just fine without the bus / driver refs so dropped for the next set.
In a previous mail you said "In this patchset the presets are easy because autofdo has a single feature and there is only 2 parameters for this feature. I worry about what things will look like when a configuration has 6 featurse, each with a varying number of parameters. Here too I don't have a clear answer on how to proceed but it will need to be revised. "
Things will look very much the same. Each row in the preset value array is an ordered list of parameter values, based on the order of features referenced in the configuration, and the order of the parameters in the feature. And the more parameters / features are in a configuration, the more useful preset sets become.
Realistically, I do not envisage huge rows of parameters in a configuration - the more degrees of freedom, then the harder it is to understand and use. I would expect users to ultimately write more than one feature / configuration and allow a small number of adjustable parameters, sufficient for the test at hand. And even with the ETM - there is a limit to the number of settings that are usefully variable at runtime.
I am open to suggestions for a better representation - but it would need to be flexible enough to be declared as a static structure for compliation in C, and also be easy to index in terms of the code used to set up the preset values when chosen.
err = cscfg_create_device();
if (err)
goto exit_drv_unregister;
INIT_LIST_HEAD(&cscfg_data.dev_list);
INIT_LIST_HEAD(&cscfg_data.feat_list);
INIT_LIST_HEAD(&cscfg_data.config_list);
cscfg_data.nr_csdev = 0;
dev_info(to_device_cscfg(), "CoreSight Configuration manager initialised");
return 0;
+exit_drv_unregister:
cscfg_driver_exit();
+exit_bus_unregister:
bus_unregister(&cscfg_bus_type);
return err;
+}
+void __exit cscfg_exit(void) +{
cscfg_clear_device();
cscfg_driver_exit();
bus_unregister(&cscfg_bus_type);
+} diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h new file mode 100644 index 000000000000..5a7896426eab --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/*
- Coresight system configuration driver.
- */
+#ifndef CORESIGHT_SYSCFG_H +#define CORESIGHT_SYSCFG_H
+#include <linux/coresight.h> +#include <linux/device.h>
+#include "coresight-config.h"
+/**
- System configuration API data.
- @dev_list: List of other coresight devices registered with this device.
- @feat_list: List of features to load into registered devices.
- @config_list:List of system configurations to load into registered devices.
- @nr_csdev: Number of registered devices with the cscfg system
- */
+struct cscfg_api_data {
struct list_head dev_list;
struct list_head feat_list;
struct list_head config_list;
int nr_csdev;
+};
+/* internal core operations for cscfg */ +int __init cscfg_init(void); +void __exit cscfg_exit(void);
+/* syscfg external API */ +int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs,
struct cscfg_feature_desc **feat_descs);
+/* system configuration device driver and API */ +/**
- System configuration device.
- Need a device to 'own' some coresight system wide sysfs entries in
- perf events etc.
- @dev: The device.
- @cfg_data: A reference to the configuration and feature lists
- */
+struct cscfg_device {
struct device dev;
struct cscfg_api_data *cfg_data;
+};
+/* basic device driver */ +struct cscfg_driver {
struct device_driver drv;
+};
+#endif /* CORESIGHT_SYSCFG_H */
2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
API for individual devices to register with the syscfg management system is added.
Devices register with matching information, and any features or configurations that match will be loaded into the device.
The feature and configuration loading is extended so that on load these are loaded into any currently registered devices. This allows configuration loading after devices have been registered.
Signed-off-by: Mike Leach mike.leach@linaro.org --- .../hwtracing/coresight/coresight-config.h | 120 ++++++ .../hwtracing/coresight/coresight-syscfg.c | 346 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 20 + include/linux/coresight.h | 7 + 4 files changed, 493 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 0d9ae1dc4517..8fd7ff991ced 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -167,4 +167,124 @@ struct cscfg_config_desc { const u64 *presets; /* nr_presets * nr_total_params */ };
+/** + * config register instance - part of a loaded feature. + * maps register values to csdev driver structures + * + * @value: value to use when setting feature on device / store for + * readback of volatile values. + * @drv_store: pointer to internal driver element used to set the value + * in hardware. + */ +struct cscfg_reg_csdev { + struct cscfg_regval value; + void *drv_store; +}; + +/** + * config parameter instance - part of a loaded feature. + * + * @feat: parent feature + * @reg: register value updated by this parameter. + * @current_value: current value of parameter - may be set by user via + * sysfs, or modified during device operation. + * @val64: true if 64 bit value + */ +struct cscfg_parameter_csdev { + struct cscfg_feature_csdev *feat; + struct cscfg_reg_csdev *reg; + u64 current_value; + bool val64; +}; + +/** + * cscfg_feat_ops - standard operations for loaded features. + * + * CS config core provides basic defaults for these, which can be overridden by + * device specific versions. + * + * @set_on_enable: Set the feature on the driver before hw enable. + * @save_on_disable: Save any volatile register values after hw disable. + * @reset: Reset feature to default values. + */ +struct cscfg_feat_ops { + int (*set_on_enable)(struct cscfg_feature_csdev *feat, const bool force_set); + void (*save_on_disable)(struct cscfg_feature_csdev *feat, const bool force_save); + void (*reset)(struct cscfg_feature_csdev *feat); +}; + +/** + * Feature instance loaded into a CoreSight device. + * + * When a feature is loaded into a specific device, then this structure holds + * the connections between the register / parameter values used and the + * internal data structures that are written when the feature is enabled. + * + * Since applying a feature modifies internal data structures in the device, + * then we have a reference to the device spinlock to protect access to these + * structures (@csdev_spinlock). + * + * @desc: pointer to the static descriptor for this feature. + * @csdev: parent CoreSight device instance. + * @node: list entry into feature list for this device. + * @csdev_spinlock: device spinlock from csdev instance.. + * @enabled: feature is enabled on this device. + * @nr_params: number of parameters. + * @params: current parameter values on this device + * @nr_regs: number of registers to be programmed. + * @regs: Programming details for the registers + * @ops: standard ops to enable and disable features on devices. + */ +struct cscfg_feature_csdev { + const struct cscfg_feature_desc *desc; + struct coresight_device *csdev; + struct list_head node; + spinlock_t *csdev_spinlock; + bool enabled; + int nr_params; + struct cscfg_parameter_csdev *params; + int nr_regs; + struct cscfg_reg_csdev *regs; + struct cscfg_feat_ops ops; +}; + +/** + * Configuration instance when loaded into a CoreSight device. + * + * The instance contains references to loaded features on this device that are + * used by the configuration. + * + * @desc: reference to the descriptor for this configuration + * @csdev: parent coresight device for this configuration instance. + * @node: list entry within the coresight device + * @id_hash: hash value of configuration name used for selection. + * @nr_feat: Number of features on this device that are used in the + * configuration. + * @feats: reference to the device features to enable. + * @enabled: true if configuration is enabled on this device. + */ +struct cscfg_config_csdev { + const struct cscfg_config_desc *desc; + struct coresight_device *csdev; + struct list_head node; + unsigned long id_hash; + int nr_feat; + struct cscfg_feature_csdev **feats; + bool enabled; +}; + +/** + * Coresight device operations.. + * + * Registered coresight devices provide these operations to manage feature + * instances compatible with the device hardware and drivers + * + * @load_feat: Pass a feature descriptor into the device and create the + * create the loaded feature instance (struct cscfg_feature_csdev). + */ +struct cscfg_csdev_feat_ops { + int (*load_feat)(struct coresight_device *csdev, + struct cscfg_feature_csdev *feat); +}; + #endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 6f89541af7a0..53bc1d551171 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -27,6 +27,198 @@ struct device *to_device_cscfg(void);
/* load features and configuations into the lists */
+/* get name feature instance from a coresight device list of features */ +static struct cscfg_feature_csdev * +cscfg_get_feat_csdev(struct coresight_device *csdev, const char *name) +{ + struct cscfg_feature_csdev *feat = NULL; + + list_for_each_entry(feat, &csdev->feat_list, node) { + if (strcmp(feat->desc->name, name) == 0) + return feat; + } + return NULL; +} + +/* allocate the device config instance - with max number of used features */ +static struct cscfg_config_csdev * +cscfg_alloc_csdev_cfg(struct coresight_device *csdev, int nr_feats) +{ + struct cscfg_config_csdev *dev_cfg = NULL; + struct device *dev = csdev->dev.parent; + + /* this is being allocated using the devm for the coresight device */ + dev_cfg = devm_kzalloc(dev, sizeof(struct cscfg_config_csdev), GFP_KERNEL); + if (!dev_cfg) + return NULL; + + dev_cfg->csdev = csdev; + dev_cfg->feats = devm_kcalloc(dev, nr_feats, + sizeof(struct cscfg_feature_csdev *), + GFP_KERNEL); + if (!dev_cfg->feats) + dev_cfg = NULL; + return dev_cfg; +} + +/* check match info between used feature from the config and a regisered device */ +static bool cscfg_match_feat_info(struct cscfg_match_info *used_cmp, + struct cscfg_match_info *reg_dev) +{ + /* if flags don't match then fail early */ + if (!(used_cmp->match_flags & reg_dev->match_flags)) + return false; + + /* if input used_cmp has a name, then check this too */ + if (used_cmp->dev_name) { + if (strcmp(used_cmp->dev_name, reg_dev->dev_name) != 0) + return false; + } + return true; +} + +/* Load a config into a device if there are feature matches between config and device */ +static int cscfg_add_csdev_cfg(struct coresight_device *csdev, + struct cscfg_match_info *match_info, + struct cscfg_config_desc *cfg_desc) +{ + struct cscfg_config_csdev *dev_cfg = NULL; + struct cscfg_config_feat_ref *feat_ref; + struct cscfg_feature_csdev *feat; + int checked; + + /* look at each required feature and see if it matches any feature on the device */ + for (checked = 0; checked < cfg_desc->nr_refs; checked++) { + feat_ref = &cfg_desc->refs[checked]; + if (cscfg_match_feat_info(&feat_ref->match, match_info)) { + /* device matched - get the feature */ + feat = cscfg_get_feat_csdev(csdev, feat_ref->name); + if (!feat) + return -EINVAL; + if (!dev_cfg) { + dev_cfg = cscfg_alloc_csdev_cfg(csdev, cfg_desc->nr_refs); + if (!dev_cfg) + return -ENOMEM; + dev_cfg->desc = cfg_desc; + } + dev_cfg->feats[dev_cfg->nr_feat++] = feat; + } + } + /* if matched features, add config to device.*/ + if (dev_cfg) + list_add(&dev_cfg->node, &csdev->syscfg_list); + + return 0; +} + +/* + * Add the config to the set of registered devices - call with mutex locked. + * Iterates through devices - any device that matches one or more of the + * configuration features will load it, the others will ignore it. + */ +static int cscfg_add_cfg_to_csdevs(struct cscfg_config_desc *cfg_desc) +{ + struct cscfg_csdev_register *curr_item; + int err; + + list_for_each_entry(curr_item, &cscfg_data.dev_list, item) { + err = cscfg_add_csdev_cfg(curr_item->csdev, &curr_item->match_info, cfg_desc); + if (err) + return err; + } + return 0; +} + +/* + * Allocate a feature object for load into a csdev. + * memory allocated using the csdev->dev object using devm managed allocator. + */ +static struct cscfg_feature_csdev * +cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc *feat_desc) +{ + struct cscfg_feature_csdev *feat = NULL; + struct device *dev = csdev->dev.parent; + int i; + + feat = devm_kzalloc(dev, sizeof(struct cscfg_feature_csdev), GFP_KERNEL); + if (!feat) + return NULL; + + /* parameters are optional - could be 0 */ + feat->nr_params = feat_desc->nr_params; + if (feat->nr_params) { + feat->params = devm_kcalloc(dev, feat->nr_params, + sizeof(struct cscfg_parameter_csdev), + GFP_KERNEL); + if (!feat->params) + return NULL; + } + + /* always have registers to program */ + feat->nr_regs = feat_desc->nr_regs; + feat->regs = devm_kcalloc(dev, feat->nr_regs, + sizeof(struct cscfg_reg_csdev), GFP_KERNEL); + if (!feat->regs) + return NULL; + + /* load the feature default values */ + feat->desc = feat_desc; + feat->csdev = csdev; + for (i = 0; i < feat->nr_params; i++) + feat->params[i].feat = feat; + + return feat; +} + +/* load one feature into one coresight device */ +static int cscfg_load_feat_csdev(struct coresight_device *csdev, + struct cscfg_feature_desc *feat_desc, + struct cscfg_csdev_feat_ops *ops) +{ + struct cscfg_feature_csdev *feat_csdev; + int err; + + if (!ops->load_feat) + return -EINVAL; + + feat_csdev = cscfg_alloc_csdev_feat(csdev, feat_desc); + if (!feat_csdev) + return -ENOMEM; + + /* load the feature into the device - may modify default ops*/ + err = ops->load_feat(csdev, feat_csdev); + if (err) + return err; + + /* add to internal csdev feature list */ + spin_lock(&csdev->cfg_lock); + list_add(&feat_csdev->node, &csdev->feat_list); + spin_unlock(&csdev->cfg_lock); + + return 0; +} + + +/* + * Add feature to any matching devices - call with mutex locked. + * Iterates through devices - any device that matches the feature will be + * called to load it. + */ +static int cscfg_add_feat_to_csdevs(struct cscfg_feature_desc *feat_desc) +{ + struct cscfg_csdev_register *curr_item; + int err; + + list_for_each_entry(curr_item, &cscfg_data.dev_list, item) { + if (curr_item->match_info.match_flags & feat_desc->match_flags) { + err = cscfg_load_feat_csdev(curr_item->csdev, feat_desc, &curr_item->ops); + if (err) + return err; + } + } + return 0; +} + /* check feature list for a named feature - call with mutex locked. */ static bool cscfg_match_list_feat(const char *name) { @@ -55,6 +247,13 @@ static int cscfg_check_feat_for_cfg(struct cscfg_config_desc *cfg_desc) */ static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc) { + int err; + + /* add feature to any matching registered devices */ + err = cscfg_add_feat_to_csdevs(feat_desc); + if (err) + return err; + list_add(&feat_desc->item, &cscfg_data.feat_list);
return 0; @@ -73,6 +272,11 @@ static int cscfg_load_config(struct cscfg_config_desc *cfg_desc) if (err) return err;
+ /* add config to any matching registered device */ + err = cscfg_add_cfg_to_csdevs(cfg_desc); + if (err) + return err; + list_add(&cfg_desc->item, &cscfg_data.config_list);
return 0; @@ -124,6 +328,148 @@ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, } EXPORT_SYMBOL_GPL(cscfg_load_config_sets);
+/* Handle coresight device registration and add configs and features to devices */ + +/* iterate through config lists and load matching configs to device */ +static int cscfg_add_cfgs_csdev(struct coresight_device *csdev, + struct cscfg_match_info *info) +{ + struct cscfg_config_desc *curr_item; + int err = 0; + + list_for_each_entry(curr_item, &cscfg_data.config_list, item) { + err = cscfg_add_csdev_cfg(csdev, info, curr_item); + if (err) + break; + } + return err; +} + +/* iterate through feature lists and load matching features to device */ +static int cscfg_add_feats_csdev(struct coresight_device *csdev, + struct cscfg_match_info *info, + struct cscfg_csdev_feat_ops *ops) +{ + struct cscfg_feature_desc *curr_item; + int err = 0; + + if (!ops->load_feat) + return -EINVAL; + + list_for_each_entry(curr_item, &cscfg_data.feat_list, item) { + if (curr_item->match_flags & info->match_flags) { + err = cscfg_load_feat_csdev(csdev, curr_item, ops); + if (err) + break; + } + } + return err; +} + +/* Add coresight device to list and copy its matching info */ +static int cscfg_list_add_csdev(struct coresight_device *csdev, + struct cscfg_match_info *info, + struct cscfg_csdev_feat_ops *ops) +{ + struct cscfg_csdev_register *list_entry; + const char *name = NULL; + + /* allocate the list entry structure */ + list_entry = kzalloc(sizeof(struct cscfg_csdev_register), GFP_KERNEL); + if (!list_entry) + return -ENOMEM; + if (info->dev_name) { + name = kstrdup(info->dev_name, GFP_KERNEL); + if (!name) { + kfree(list_entry); + return -ENOMEM; + } + } + + list_entry->csdev = csdev; + list_entry->match_info.match_flags = info->match_flags; + list_entry->match_info.dev_name = name; + list_entry->ops.load_feat = ops->load_feat; + list_add(&list_entry->item, &cscfg_data.dev_list); + + INIT_LIST_HEAD(&csdev->feat_list); + INIT_LIST_HEAD(&csdev->syscfg_list); + spin_lock_init(&csdev->cfg_lock); + cscfg_data.nr_csdev++; + + return 0; +} + +/* remove a coresight device from the list and free data */ +static void cscfg_list_remove_csdev(struct coresight_device *csdev) +{ + struct cscfg_csdev_register *curr_item, *tmp; + + list_for_each_entry_safe(curr_item, tmp, &cscfg_data.dev_list, item) { + if (curr_item->csdev == csdev) { + list_del(&curr_item->item); + kfree(curr_item->match_info.dev_name); + kfree(curr_item); + cscfg_data.nr_csdev--; + break; + } + } +} + +/* register a coresight device with the syscfg api */ +int cscfg_register_csdev(struct coresight_device *csdev, + struct cscfg_match_info *info, + struct cscfg_csdev_feat_ops *ops) +{ + int ret = 0; + + mutex_lock(&cscfg_mutex); + + /* add device to list of registered devices */ + ret = cscfg_list_add_csdev(csdev, info, ops); + if (ret) + goto reg_csdev_unlock; + + /* now load any registered features and configs matching the device. */ + ret = cscfg_add_feats_csdev(csdev, info, ops); + if (ret) { + cscfg_list_remove_csdev(csdev); + goto reg_csdev_unlock; + } + + ret = cscfg_add_cfgs_csdev(csdev, info); + if (ret) { + cscfg_list_remove_csdev(csdev); + goto reg_csdev_unlock; + } + + pr_info("CSCFG registered %s", dev_name(&csdev->dev)); + +reg_csdev_unlock: + mutex_unlock(&cscfg_mutex); + return ret; +} +EXPORT_SYMBOL_GPL(cscfg_register_csdev); + +/* remove coresight device and update counts - syscfg device at 0 */ +void cscfg_unregister_csdev(struct coresight_device *csdev) +{ + struct cscfg_csdev_register *curr_item, *tmp; + + mutex_lock(&cscfg_mutex); + list_for_each_entry_safe(curr_item, tmp, &cscfg_data.dev_list, item) { + if (curr_item->csdev == csdev) { + list_del(&curr_item->item); + kfree(curr_item->match_info.dev_name); + kfree(curr_item); + cscfg_data.nr_csdev--; + break; + } + } + mutex_unlock(&cscfg_mutex); +} +EXPORT_SYMBOL_GPL(cscfg_unregister_csdev); + /* Initialise system configuration management driver. */ /* only one of these */ static struct cscfg_device *cscfg_dev; diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 5a7896426eab..ecf4aac7d712 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -26,6 +26,22 @@ struct cscfg_api_data { int nr_csdev; };
+/** + * List entry for Coresight devices that are registered as supporting complex + * config operations. + * + * @csdev: The registered device. + * @match_info: The matching type information. + * @ops: Operations supported by the registered device. + * @item: list entry. + */ +struct cscfg_csdev_register { + struct coresight_device *csdev; + struct cscfg_match_info match_info; + struct cscfg_csdev_feat_ops ops; + struct list_head item; +}; + /* internal core operations for cscfg */ int __init cscfg_init(void); void __exit cscfg_exit(void); @@ -33,6 +49,10 @@ void __exit cscfg_exit(void); /* syscfg external API */ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, struct cscfg_feature_desc **feat_descs); +int cscfg_register_csdev(struct coresight_device *csdev, + struct cscfg_match_info *info, + struct cscfg_csdev_feat_ops *ops); +void cscfg_unregister_csdev(struct coresight_device *csdev);
/* system configuration device driver and API */ /** diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 7d3c87e5b97c..bade9e8ac20c 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -189,6 +189,9 @@ struct coresight_sysfs_link { * @nr_links: number of sysfs links created to other components from this * device. These will appear in the "connections" group. * @has_conns_grp: Have added a "connections" group for sysfs links. + * @feat_list: List of complex feature programming added to the device. + * @syscfg_list: List of system configurations added to the device. + * @cfg_lock: spinlock to protect feature and config lists for this device. */ struct coresight_device { struct coresight_platform_data *pdata; @@ -209,6 +212,10 @@ struct coresight_device { int nr_links; bool has_conns_grp; bool ect_enabled; /* true only if associated ect device is enabled */ + /* complex config and feature lists */ + struct list_head feat_list; + struct list_head syscfg_list; + spinlock_t cfg_lock; };
/*
On Fri, Oct 30, 2020 at 05:56:48PM +0000, Mike Leach wrote:
API for individual devices to register with the syscfg management system is added.
Devices register with matching information, and any features or configurations that match will be loaded into the device.
The feature and configuration loading is extended so that on load these are loaded into any currently registered devices. This allows configuration loading after devices have been registered.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-config.h | 120 ++++++ .../hwtracing/coresight/coresight-syscfg.c | 346 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 20 + include/linux/coresight.h | 7 + 4 files changed, 493 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 0d9ae1dc4517..8fd7ff991ced 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -167,4 +167,124 @@ struct cscfg_config_desc { const u64 *presets; /* nr_presets * nr_total_params */ }; +/**
- config register instance - part of a loaded feature.
maps register values to csdev driver structures
- @value: value to use when setting feature on device / store for
readback of volatile values.
- @drv_store: pointer to internal driver element used to set the value
in hardware.
- */
+struct cscfg_reg_csdev {
- struct cscfg_regval value;
- void *drv_store;
+};
+/**
- config parameter instance - part of a loaded feature.
- @feat: parent feature
- @reg: register value updated by this parameter.
- @current_value: current value of parameter - may be set by user via
sysfs, or modified during device operation.
- @val64: true if 64 bit value
- */
+struct cscfg_parameter_csdev {
- struct cscfg_feature_csdev *feat;
- struct cscfg_reg_csdev *reg;
- u64 current_value;
- bool val64;
+};
+/**
- cscfg_feat_ops - standard operations for loaded features.
- CS config core provides basic defaults for these, which can be overridden by
- device specific versions.
- @set_on_enable: Set the feature on the driver before hw enable.
- @save_on_disable: Save any volatile register values after hw disable.
- @reset: Reset feature to default values.
- */
+struct cscfg_feat_ops {
- int (*set_on_enable)(struct cscfg_feature_csdev *feat, const bool force_set);
- void (*save_on_disable)(struct cscfg_feature_csdev *feat, const bool force_save);
- void (*reset)(struct cscfg_feature_csdev *feat);
+};
+/**
- Feature instance loaded into a CoreSight device.
- When a feature is loaded into a specific device, then this structure holds
- the connections between the register / parameter values used and the
- internal data structures that are written when the feature is enabled.
- Since applying a feature modifies internal data structures in the device,
- then we have a reference to the device spinlock to protect access to these
- structures (@csdev_spinlock).
- @desc: pointer to the static descriptor for this feature.
- @csdev: parent CoreSight device instance.
- @node: list entry into feature list for this device.
- @csdev_spinlock: device spinlock from csdev instance..
- @enabled: feature is enabled on this device.
- @nr_params: number of parameters.
- @params: current parameter values on this device
- @nr_regs: number of registers to be programmed.
- @regs: Programming details for the registers
- @ops: standard ops to enable and disable features on devices.
- */
+struct cscfg_feature_csdev {
- const struct cscfg_feature_desc *desc;
- struct coresight_device *csdev;
- struct list_head node;
- spinlock_t *csdev_spinlock;
- bool enabled;
- int nr_params;
- struct cscfg_parameter_csdev *params;
- int nr_regs;
- struct cscfg_reg_csdev *regs;
- struct cscfg_feat_ops ops;
+};
+/**
- Configuration instance when loaded into a CoreSight device.
- The instance contains references to loaded features on this device that are
- used by the configuration.
- @desc: reference to the descriptor for this configuration
- @csdev: parent coresight device for this configuration instance.
- @node: list entry within the coresight device
- @id_hash: hash value of configuration name used for selection.
- @nr_feat: Number of features on this device that are used in the
configuration.
- @feats: reference to the device features to enable.
- @enabled: true if configuration is enabled on this device.
- */
+struct cscfg_config_csdev {
- const struct cscfg_config_desc *desc;
- struct coresight_device *csdev;
- struct list_head node;
- unsigned long id_hash;
- int nr_feat;
- struct cscfg_feature_csdev **feats;
- bool enabled;
+};
+/**
- Coresight device operations..
Two dots
- Registered coresight devices provide these operations to manage feature
- instances compatible with the device hardware and drivers
- @load_feat: Pass a feature descriptor into the device and create the
create the loaded feature instance (struct cscfg_feature_csdev).
"create the" is there twice.
- */
+struct cscfg_csdev_feat_ops {
- int (*load_feat)(struct coresight_device *csdev,
struct cscfg_feature_csdev *feat);
+};
#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 6f89541af7a0..53bc1d551171 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -27,6 +27,198 @@ struct device *to_device_cscfg(void); /* load features and configuations into the lists */ +/* get name feature instance from a coresight device list of features */ +static struct cscfg_feature_csdev * +cscfg_get_feat_csdev(struct coresight_device *csdev, const char *name) +{
- struct cscfg_feature_csdev *feat = NULL;
- list_for_each_entry(feat, &csdev->feat_list, node) {
if (strcmp(feat->desc->name, name) == 0)
return feat;
- }
- return NULL;
+}
+/* allocate the device config instance - with max number of used features */ +static struct cscfg_config_csdev * +cscfg_alloc_csdev_cfg(struct coresight_device *csdev, int nr_feats) +{
- struct cscfg_config_csdev *dev_cfg = NULL;
- struct device *dev = csdev->dev.parent;
- /* this is being allocated using the devm for the coresight device */
- dev_cfg = devm_kzalloc(dev, sizeof(struct cscfg_config_csdev), GFP_KERNEL);
- if (!dev_cfg)
return NULL;
- dev_cfg->csdev = csdev;
- dev_cfg->feats = devm_kcalloc(dev, nr_feats,
sizeof(struct cscfg_feature_csdev *),
GFP_KERNEL);
- if (!dev_cfg->feats)
dev_cfg = NULL;
- return dev_cfg;
+}
+/* check match info between used feature from the config and a regisered device */ +static bool cscfg_match_feat_info(struct cscfg_match_info *used_cmp,
struct cscfg_match_info *reg_dev)
+{
- /* if flags don't match then fail early */
- if (!(used_cmp->match_flags & reg_dev->match_flags))
return false;
- /* if input used_cmp has a name, then check this too */
- if (used_cmp->dev_name) {
if (strcmp(used_cmp->dev_name, reg_dev->dev_name) != 0)
return false;
- }
- return true;
+}
+/* Load a config into a device if there are feature matches between config and device */ +static int cscfg_add_csdev_cfg(struct coresight_device *csdev,
struct cscfg_match_info *match_info,
struct cscfg_config_desc *cfg_desc)
+{
- struct cscfg_config_csdev *dev_cfg = NULL;
- struct cscfg_config_feat_ref *feat_ref;
- struct cscfg_feature_csdev *feat;
- int checked;
- /* look at each required feature and see if it matches any feature on the device */
- for (checked = 0; checked < cfg_desc->nr_refs; checked++) {
feat_ref = &cfg_desc->refs[checked];
if (cscfg_match_feat_info(&feat_ref->match, match_info)) {
/* device matched - get the feature */
feat = cscfg_get_feat_csdev(csdev, feat_ref->name);
if (!feat)
return -EINVAL;
if (!dev_cfg) {
dev_cfg = cscfg_alloc_csdev_cfg(csdev, cfg_desc->nr_refs);
if (!dev_cfg)
return -ENOMEM;
dev_cfg->desc = cfg_desc;
}
dev_cfg->feats[dev_cfg->nr_feat++] = feat;
}
- }
- /* if matched features, add config to device.*/
- if (dev_cfg)
list_add(&dev_cfg->node, &csdev->syscfg_list);
- return 0;
+}
+/*
- Add the config to the set of registered devices - call with mutex locked.
- Iterates through devices - any device that matches one or more of the
- configuration features will load it, the others will ignore it.
- */
+static int cscfg_add_cfg_to_csdevs(struct cscfg_config_desc *cfg_desc) +{
- struct cscfg_csdev_register *curr_item;
- int err;
- list_for_each_entry(curr_item, &cscfg_data.dev_list, item) {
err = cscfg_add_csdev_cfg(curr_item->csdev, &curr_item->match_info, cfg_desc);
if (err)
return err;
- }
- return 0;
+}
+/*
- Allocate a feature object for load into a csdev.
- memory allocated using the csdev->dev object using devm managed allocator.
- */
+static struct cscfg_feature_csdev * +cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc *feat_desc) +{
- struct cscfg_feature_csdev *feat = NULL;
- struct device *dev = csdev->dev.parent;
- int i;
- feat = devm_kzalloc(dev, sizeof(struct cscfg_feature_csdev), GFP_KERNEL);
- if (!feat)
return NULL;
- /* parameters are optional - could be 0 */
- feat->nr_params = feat_desc->nr_params;
- if (feat->nr_params) {
feat->params = devm_kcalloc(dev, feat->nr_params,
sizeof(struct cscfg_parameter_csdev),
GFP_KERNEL);
if (!feat->params)
return NULL;
- }
- /* always have registers to program */
- feat->nr_regs = feat_desc->nr_regs;
- feat->regs = devm_kcalloc(dev, feat->nr_regs,
sizeof(struct cscfg_reg_csdev), GFP_KERNEL);
Arrays feat->params and feat-regs are allocated but not initialised with anything. It would be nice to have a comment that mentions where values will be set.
- if (!feat->regs)
return NULL;
- /* load the feature default values */
- feat->desc = feat_desc;
- feat->csdev = csdev;
- for (i = 0; i < feat->nr_params; i++)
feat->params[i].feat = feat;
- return feat;
+}
+/* load one feature into one coresight device */ +static int cscfg_load_feat_csdev(struct coresight_device *csdev,
struct cscfg_feature_desc *feat_desc,
struct cscfg_csdev_feat_ops *ops)
+{
- struct cscfg_feature_csdev *feat_csdev;
- int err;
- if (!ops->load_feat)
return -EINVAL;
- feat_csdev = cscfg_alloc_csdev_feat(csdev, feat_desc);
- if (!feat_csdev)
return -ENOMEM;
- /* load the feature into the device - may modify default ops*/
- err = ops->load_feat(csdev, feat_csdev);
- if (err)
return err;
- /* add to internal csdev feature list */
- spin_lock(&csdev->cfg_lock);
- list_add(&feat_csdev->node, &csdev->feat_list);
- spin_unlock(&csdev->cfg_lock);
- return 0;
+}
Extra line
+/*
- Add feature to any matching devices - call with mutex locked.
- Iterates through devices - any device that matches the feature will be
- called to load it.
- */
+static int cscfg_add_feat_to_csdevs(struct cscfg_feature_desc *feat_desc) +{
- struct cscfg_csdev_register *curr_item;
- int err;
- list_for_each_entry(curr_item, &cscfg_data.dev_list, item) {
if (curr_item->match_info.match_flags & feat_desc->match_flags) {
err = cscfg_load_feat_csdev(curr_item->csdev, feat_desc, &curr_item->ops);
if (err)
return err;
}
- }
- return 0;
+}
/* check feature list for a named feature - call with mutex locked. */ static bool cscfg_match_list_feat(const char *name) { @@ -55,6 +247,13 @@ static int cscfg_check_feat_for_cfg(struct cscfg_config_desc *cfg_desc) */ static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc) {
- int err;
- /* add feature to any matching registered devices */
- err = cscfg_add_feat_to_csdevs(feat_desc);
- if (err)
return err;
- list_add(&feat_desc->item, &cscfg_data.feat_list);
return 0; @@ -73,6 +272,11 @@ static int cscfg_load_config(struct cscfg_config_desc *cfg_desc) if (err) return err;
- /* add config to any matching registered device */
- err = cscfg_add_cfg_to_csdevs(cfg_desc);
- if (err)
return err;
- list_add(&cfg_desc->item, &cscfg_data.config_list);
return 0; @@ -124,6 +328,148 @@ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, } EXPORT_SYMBOL_GPL(cscfg_load_config_sets); +/* Handle coresight device registration and add configs and features to devices */
+/* iterate through config lists and load matching configs to device */ +static int cscfg_add_cfgs_csdev(struct coresight_device *csdev,
struct cscfg_match_info *info)
+{
- struct cscfg_config_desc *curr_item;
- int err = 0;
- list_for_each_entry(curr_item, &cscfg_data.config_list, item) {
err = cscfg_add_csdev_cfg(csdev, info, curr_item);
if (err)
break;
- }
- return err;
+}
+/* iterate through feature lists and load matching features to device */ +static int cscfg_add_feats_csdev(struct coresight_device *csdev,
struct cscfg_match_info *info,
struct cscfg_csdev_feat_ops *ops)
+{
- struct cscfg_feature_desc *curr_item;
- int err = 0;
- if (!ops->load_feat)
return -EINVAL;
- list_for_each_entry(curr_item, &cscfg_data.feat_list, item) {
if (curr_item->match_flags & info->match_flags) {
err = cscfg_load_feat_csdev(csdev, curr_item, ops);
if (err)
break;
}
- }
- return err;
+}
+/* Add coresight device to list and copy its matching info */ +static int cscfg_list_add_csdev(struct coresight_device *csdev,
struct cscfg_match_info *info,
struct cscfg_csdev_feat_ops *ops)
+{
- struct cscfg_csdev_register *list_entry;
- const char *name = NULL;
- /* allocate the list entry structure */
- list_entry = kzalloc(sizeof(struct cscfg_csdev_register), GFP_KERNEL);
- if (!list_entry)
return -ENOMEM;
- if (info->dev_name) {
name = kstrdup(info->dev_name, GFP_KERNEL);
if (!name) {
kfree(list_entry);
return -ENOMEM;
}
- }
- list_entry->csdev = csdev;
- list_entry->match_info.match_flags = info->match_flags;
- list_entry->match_info.dev_name = name;
- list_entry->ops.load_feat = ops->load_feat;
- list_add(&list_entry->item, &cscfg_data.dev_list);
- INIT_LIST_HEAD(&csdev->feat_list);
- INIT_LIST_HEAD(&csdev->syscfg_list);
- spin_lock_init(&csdev->cfg_lock);
- cscfg_data.nr_csdev++;
- return 0;
+}
+/* remove a coresight device from the list and free data */ +static void cscfg_list_remove_csdev(struct coresight_device *csdev) +{
- struct cscfg_csdev_register *curr_item, *tmp;
- list_for_each_entry_safe(curr_item, tmp, &cscfg_data.dev_list, item) {
if (curr_item->csdev == csdev) {
list_del(&curr_item->item);
kfree(curr_item->match_info.dev_name);
kfree(curr_item);
cscfg_data.nr_csdev--;
break;
}
- }
+}
+/* register a coresight device with the syscfg api */ +int cscfg_register_csdev(struct coresight_device *csdev,
struct cscfg_match_info *info,
struct cscfg_csdev_feat_ops *ops)
+{
- int ret = 0;
- mutex_lock(&cscfg_mutex);
- /* add device to list of registered devices */
- ret = cscfg_list_add_csdev(csdev, info, ops);
- if (ret)
goto reg_csdev_unlock;
- /* now load any registered features and configs matching the device. */
- ret = cscfg_add_feats_csdev(csdev, info, ops);
- if (ret) {
cscfg_list_remove_csdev(csdev);
goto reg_csdev_unlock;
- }
- ret = cscfg_add_cfgs_csdev(csdev, info);
- if (ret) {
cscfg_list_remove_csdev(csdev);
goto reg_csdev_unlock;
- }
- pr_info("CSCFG registered %s", dev_name(&csdev->dev));
+reg_csdev_unlock:
- mutex_unlock(&cscfg_mutex);
- return ret;
+} +EXPORT_SYMBOL_GPL(cscfg_register_csdev);
+/* remove coresight device and update counts - syscfg device at 0 */ +void cscfg_unregister_csdev(struct coresight_device *csdev) +{
- struct cscfg_csdev_register *curr_item, *tmp;
- mutex_lock(&cscfg_mutex);
- list_for_each_entry_safe(curr_item, tmp, &cscfg_data.dev_list, item) {
if (curr_item->csdev == csdev) {
list_del(&curr_item->item);
kfree(curr_item->match_info.dev_name);
kfree(curr_item);
cscfg_data.nr_csdev--;
break;
}
- }
- mutex_unlock(&cscfg_mutex);
+} +EXPORT_SYMBOL_GPL(cscfg_unregister_csdev);
/* Initialise system configuration management driver. */ /* only one of these */ static struct cscfg_device *cscfg_dev; diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 5a7896426eab..ecf4aac7d712 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -26,6 +26,22 @@ struct cscfg_api_data { int nr_csdev; }; +/**
- List entry for Coresight devices that are registered as supporting complex
- config operations.
- @csdev: The registered device.
- @match_info: The matching type information.
- @ops: Operations supported by the registered device.
- @item: list entry.
- */
+struct cscfg_csdev_register {
- struct coresight_device *csdev;
- struct cscfg_match_info match_info;
- struct cscfg_csdev_feat_ops ops;
- struct list_head item;
+};
/* internal core operations for cscfg */ int __init cscfg_init(void); void __exit cscfg_exit(void); @@ -33,6 +49,10 @@ void __exit cscfg_exit(void); /* syscfg external API */ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, struct cscfg_feature_desc **feat_descs); +int cscfg_register_csdev(struct coresight_device *csdev,
struct cscfg_match_info *info,
struct cscfg_csdev_feat_ops *ops);
+void cscfg_unregister_csdev(struct coresight_device *csdev); /* system configuration device driver and API */ /** diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 7d3c87e5b97c..bade9e8ac20c 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -189,6 +189,9 @@ struct coresight_sysfs_link {
- @nr_links: number of sysfs links created to other components from this
device. These will appear in the "connections" group.
- @has_conns_grp: Have added a "connections" group for sysfs links.
- @feat_list: List of complex feature programming added to the device.
- @syscfg_list: List of system configurations added to the device.
*/
- @cfg_lock: spinlock to protect feature and config lists for this device.
struct coresight_device { struct coresight_platform_data *pdata; @@ -209,6 +212,10 @@ struct coresight_device { int nr_links; bool has_conns_grp; bool ect_enabled; /* true only if associated ect device is enabled */
- /* complex config and feature lists */
- struct list_head feat_list;
- struct list_head syscfg_list;
I would name the above feature_csdev_list and config_csdev_list. That way it matches the declaration of cscfg_feature_csdev and cscf_config_csdev and we know exactly what is enqueued on the lists.
- spinlock_t cfg_lock;
}; /* -- 2.17.1
HI MAthieu,
Thanks - I've done what you suggest in this patch.
Mike
On Mon, 16 Nov 2020 at 18:47, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Fri, Oct 30, 2020 at 05:56:48PM +0000, Mike Leach wrote:
API for individual devices to register with the syscfg management system is added.
Devices register with matching information, and any features or configurations that match will be loaded into the device.
The feature and configuration loading is extended so that on load these are loaded into any currently registered devices. This allows configuration loading after devices have been registered.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-config.h | 120 ++++++ .../hwtracing/coresight/coresight-syscfg.c | 346 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 20 + include/linux/coresight.h | 7 + 4 files changed, 493 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 0d9ae1dc4517..8fd7ff991ced 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -167,4 +167,124 @@ struct cscfg_config_desc { const u64 *presets; /* nr_presets * nr_total_params */ };
+/**
- config register instance - part of a loaded feature.
maps register values to csdev driver structures
- @value: value to use when setting feature on device / store for
readback of volatile values.
- @drv_store: pointer to internal driver element used to set the value
in hardware.
- */
+struct cscfg_reg_csdev {
struct cscfg_regval value;
void *drv_store;
+};
+/**
- config parameter instance - part of a loaded feature.
- @feat: parent feature
- @reg: register value updated by this parameter.
- @current_value: current value of parameter - may be set by user via
sysfs, or modified during device operation.
- @val64: true if 64 bit value
- */
+struct cscfg_parameter_csdev {
struct cscfg_feature_csdev *feat;
struct cscfg_reg_csdev *reg;
u64 current_value;
bool val64;
+};
+/**
- cscfg_feat_ops - standard operations for loaded features.
- CS config core provides basic defaults for these, which can be overridden by
- device specific versions.
- @set_on_enable: Set the feature on the driver before hw enable.
- @save_on_disable: Save any volatile register values after hw disable.
- @reset: Reset feature to default values.
- */
+struct cscfg_feat_ops {
int (*set_on_enable)(struct cscfg_feature_csdev *feat, const bool force_set);
void (*save_on_disable)(struct cscfg_feature_csdev *feat, const bool force_save);
void (*reset)(struct cscfg_feature_csdev *feat);
+};
+/**
- Feature instance loaded into a CoreSight device.
- When a feature is loaded into a specific device, then this structure holds
- the connections between the register / parameter values used and the
- internal data structures that are written when the feature is enabled.
- Since applying a feature modifies internal data structures in the device,
- then we have a reference to the device spinlock to protect access to these
- structures (@csdev_spinlock).
- @desc: pointer to the static descriptor for this feature.
- @csdev: parent CoreSight device instance.
- @node: list entry into feature list for this device.
- @csdev_spinlock: device spinlock from csdev instance..
- @enabled: feature is enabled on this device.
- @nr_params: number of parameters.
- @params: current parameter values on this device
- @nr_regs: number of registers to be programmed.
- @regs: Programming details for the registers
- @ops: standard ops to enable and disable features on devices.
- */
+struct cscfg_feature_csdev {
const struct cscfg_feature_desc *desc;
struct coresight_device *csdev;
struct list_head node;
spinlock_t *csdev_spinlock;
bool enabled;
int nr_params;
struct cscfg_parameter_csdev *params;
int nr_regs;
struct cscfg_reg_csdev *regs;
struct cscfg_feat_ops ops;
+};
+/**
- Configuration instance when loaded into a CoreSight device.
- The instance contains references to loaded features on this device that are
- used by the configuration.
- @desc: reference to the descriptor for this configuration
- @csdev: parent coresight device for this configuration instance.
- @node: list entry within the coresight device
- @id_hash: hash value of configuration name used for selection.
- @nr_feat: Number of features on this device that are used in the
configuration.
- @feats: reference to the device features to enable.
- @enabled: true if configuration is enabled on this device.
- */
+struct cscfg_config_csdev {
const struct cscfg_config_desc *desc;
struct coresight_device *csdev;
struct list_head node;
unsigned long id_hash;
int nr_feat;
struct cscfg_feature_csdev **feats;
bool enabled;
+};
+/**
- Coresight device operations..
Two dots
- Registered coresight devices provide these operations to manage feature
- instances compatible with the device hardware and drivers
- @load_feat: Pass a feature descriptor into the device and create the
create the loaded feature instance (struct cscfg_feature_csdev).
"create the" is there twice.
- */
+struct cscfg_csdev_feat_ops {
int (*load_feat)(struct coresight_device *csdev,
struct cscfg_feature_csdev *feat);
+};
#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 6f89541af7a0..53bc1d551171 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -27,6 +27,198 @@ struct device *to_device_cscfg(void);
/* load features and configuations into the lists */
+/* get name feature instance from a coresight device list of features */ +static struct cscfg_feature_csdev * +cscfg_get_feat_csdev(struct coresight_device *csdev, const char *name) +{
struct cscfg_feature_csdev *feat = NULL;
list_for_each_entry(feat, &csdev->feat_list, node) {
if (strcmp(feat->desc->name, name) == 0)
return feat;
}
return NULL;
+}
+/* allocate the device config instance - with max number of used features */ +static struct cscfg_config_csdev * +cscfg_alloc_csdev_cfg(struct coresight_device *csdev, int nr_feats) +{
struct cscfg_config_csdev *dev_cfg = NULL;
struct device *dev = csdev->dev.parent;
/* this is being allocated using the devm for the coresight device */
dev_cfg = devm_kzalloc(dev, sizeof(struct cscfg_config_csdev), GFP_KERNEL);
if (!dev_cfg)
return NULL;
dev_cfg->csdev = csdev;
dev_cfg->feats = devm_kcalloc(dev, nr_feats,
sizeof(struct cscfg_feature_csdev *),
GFP_KERNEL);
if (!dev_cfg->feats)
dev_cfg = NULL;
return dev_cfg;
+}
+/* check match info between used feature from the config and a regisered device */ +static bool cscfg_match_feat_info(struct cscfg_match_info *used_cmp,
struct cscfg_match_info *reg_dev)
+{
/* if flags don't match then fail early */
if (!(used_cmp->match_flags & reg_dev->match_flags))
return false;
/* if input used_cmp has a name, then check this too */
if (used_cmp->dev_name) {
if (strcmp(used_cmp->dev_name, reg_dev->dev_name) != 0)
return false;
}
return true;
+}
+/* Load a config into a device if there are feature matches between config and device */ +static int cscfg_add_csdev_cfg(struct coresight_device *csdev,
struct cscfg_match_info *match_info,
struct cscfg_config_desc *cfg_desc)
+{
struct cscfg_config_csdev *dev_cfg = NULL;
struct cscfg_config_feat_ref *feat_ref;
struct cscfg_feature_csdev *feat;
int checked;
/* look at each required feature and see if it matches any feature on the device */
for (checked = 0; checked < cfg_desc->nr_refs; checked++) {
feat_ref = &cfg_desc->refs[checked];
if (cscfg_match_feat_info(&feat_ref->match, match_info)) {
/* device matched - get the feature */
feat = cscfg_get_feat_csdev(csdev, feat_ref->name);
if (!feat)
return -EINVAL;
if (!dev_cfg) {
dev_cfg = cscfg_alloc_csdev_cfg(csdev, cfg_desc->nr_refs);
if (!dev_cfg)
return -ENOMEM;
dev_cfg->desc = cfg_desc;
}
dev_cfg->feats[dev_cfg->nr_feat++] = feat;
}
}
/* if matched features, add config to device.*/
if (dev_cfg)
list_add(&dev_cfg->node, &csdev->syscfg_list);
return 0;
+}
+/*
- Add the config to the set of registered devices - call with mutex locked.
- Iterates through devices - any device that matches one or more of the
- configuration features will load it, the others will ignore it.
- */
+static int cscfg_add_cfg_to_csdevs(struct cscfg_config_desc *cfg_desc) +{
struct cscfg_csdev_register *curr_item;
int err;
list_for_each_entry(curr_item, &cscfg_data.dev_list, item) {
err = cscfg_add_csdev_cfg(curr_item->csdev, &curr_item->match_info, cfg_desc);
if (err)
return err;
}
return 0;
+}
+/*
- Allocate a feature object for load into a csdev.
- memory allocated using the csdev->dev object using devm managed allocator.
- */
+static struct cscfg_feature_csdev * +cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc *feat_desc) +{
struct cscfg_feature_csdev *feat = NULL;
struct device *dev = csdev->dev.parent;
int i;
feat = devm_kzalloc(dev, sizeof(struct cscfg_feature_csdev), GFP_KERNEL);
if (!feat)
return NULL;
/* parameters are optional - could be 0 */
feat->nr_params = feat_desc->nr_params;
if (feat->nr_params) {
feat->params = devm_kcalloc(dev, feat->nr_params,
sizeof(struct cscfg_parameter_csdev),
GFP_KERNEL);
if (!feat->params)
return NULL;
}
/* always have registers to program */
feat->nr_regs = feat_desc->nr_regs;
feat->regs = devm_kcalloc(dev, feat->nr_regs,
sizeof(struct cscfg_reg_csdev), GFP_KERNEL);
Arrays feat->params and feat-regs are allocated but not initialised with anything. It would be nice to have a comment that mentions where values will be set.
if (!feat->regs)
return NULL;
/* load the feature default values */
feat->desc = feat_desc;
feat->csdev = csdev;
for (i = 0; i < feat->nr_params; i++)
feat->params[i].feat = feat;
return feat;
+}
+/* load one feature into one coresight device */ +static int cscfg_load_feat_csdev(struct coresight_device *csdev,
struct cscfg_feature_desc *feat_desc,
struct cscfg_csdev_feat_ops *ops)
+{
struct cscfg_feature_csdev *feat_csdev;
int err;
if (!ops->load_feat)
return -EINVAL;
feat_csdev = cscfg_alloc_csdev_feat(csdev, feat_desc);
if (!feat_csdev)
return -ENOMEM;
/* load the feature into the device - may modify default ops*/
err = ops->load_feat(csdev, feat_csdev);
if (err)
return err;
/* add to internal csdev feature list */
spin_lock(&csdev->cfg_lock);
list_add(&feat_csdev->node, &csdev->feat_list);
spin_unlock(&csdev->cfg_lock);
return 0;
+}
Extra line
+/*
- Add feature to any matching devices - call with mutex locked.
- Iterates through devices - any device that matches the feature will be
- called to load it.
- */
+static int cscfg_add_feat_to_csdevs(struct cscfg_feature_desc *feat_desc) +{
struct cscfg_csdev_register *curr_item;
int err;
list_for_each_entry(curr_item, &cscfg_data.dev_list, item) {
if (curr_item->match_info.match_flags & feat_desc->match_flags) {
err = cscfg_load_feat_csdev(curr_item->csdev, feat_desc, &curr_item->ops);
if (err)
return err;
}
}
return 0;
+}
/* check feature list for a named feature - call with mutex locked. */ static bool cscfg_match_list_feat(const char *name) { @@ -55,6 +247,13 @@ static int cscfg_check_feat_for_cfg(struct cscfg_config_desc *cfg_desc) */ static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc) {
int err;
/* add feature to any matching registered devices */
err = cscfg_add_feat_to_csdevs(feat_desc);
if (err)
return err;
list_add(&feat_desc->item, &cscfg_data.feat_list); return 0;
@@ -73,6 +272,11 @@ static int cscfg_load_config(struct cscfg_config_desc *cfg_desc) if (err) return err;
/* add config to any matching registered device */
err = cscfg_add_cfg_to_csdevs(cfg_desc);
if (err)
return err;
list_add(&cfg_desc->item, &cscfg_data.config_list); return 0;
@@ -124,6 +328,148 @@ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, } EXPORT_SYMBOL_GPL(cscfg_load_config_sets);
+/* Handle coresight device registration and add configs and features to devices */
+/* iterate through config lists and load matching configs to device */ +static int cscfg_add_cfgs_csdev(struct coresight_device *csdev,
struct cscfg_match_info *info)
+{
struct cscfg_config_desc *curr_item;
int err = 0;
list_for_each_entry(curr_item, &cscfg_data.config_list, item) {
err = cscfg_add_csdev_cfg(csdev, info, curr_item);
if (err)
break;
}
return err;
+}
+/* iterate through feature lists and load matching features to device */ +static int cscfg_add_feats_csdev(struct coresight_device *csdev,
struct cscfg_match_info *info,
struct cscfg_csdev_feat_ops *ops)
+{
struct cscfg_feature_desc *curr_item;
int err = 0;
if (!ops->load_feat)
return -EINVAL;
list_for_each_entry(curr_item, &cscfg_data.feat_list, item) {
if (curr_item->match_flags & info->match_flags) {
err = cscfg_load_feat_csdev(csdev, curr_item, ops);
if (err)
break;
}
}
return err;
+}
+/* Add coresight device to list and copy its matching info */ +static int cscfg_list_add_csdev(struct coresight_device *csdev,
struct cscfg_match_info *info,
struct cscfg_csdev_feat_ops *ops)
+{
struct cscfg_csdev_register *list_entry;
const char *name = NULL;
/* allocate the list entry structure */
list_entry = kzalloc(sizeof(struct cscfg_csdev_register), GFP_KERNEL);
if (!list_entry)
return -ENOMEM;
if (info->dev_name) {
name = kstrdup(info->dev_name, GFP_KERNEL);
if (!name) {
kfree(list_entry);
return -ENOMEM;
}
}
list_entry->csdev = csdev;
list_entry->match_info.match_flags = info->match_flags;
list_entry->match_info.dev_name = name;
list_entry->ops.load_feat = ops->load_feat;
list_add(&list_entry->item, &cscfg_data.dev_list);
INIT_LIST_HEAD(&csdev->feat_list);
INIT_LIST_HEAD(&csdev->syscfg_list);
spin_lock_init(&csdev->cfg_lock);
cscfg_data.nr_csdev++;
return 0;
+}
+/* remove a coresight device from the list and free data */ +static void cscfg_list_remove_csdev(struct coresight_device *csdev) +{
struct cscfg_csdev_register *curr_item, *tmp;
list_for_each_entry_safe(curr_item, tmp, &cscfg_data.dev_list, item) {
if (curr_item->csdev == csdev) {
list_del(&curr_item->item);
kfree(curr_item->match_info.dev_name);
kfree(curr_item);
cscfg_data.nr_csdev--;
break;
}
}
+}
+/* register a coresight device with the syscfg api */ +int cscfg_register_csdev(struct coresight_device *csdev,
struct cscfg_match_info *info,
struct cscfg_csdev_feat_ops *ops)
+{
int ret = 0;
mutex_lock(&cscfg_mutex);
/* add device to list of registered devices */
ret = cscfg_list_add_csdev(csdev, info, ops);
if (ret)
goto reg_csdev_unlock;
/* now load any registered features and configs matching the device. */
ret = cscfg_add_feats_csdev(csdev, info, ops);
if (ret) {
cscfg_list_remove_csdev(csdev);
goto reg_csdev_unlock;
}
ret = cscfg_add_cfgs_csdev(csdev, info);
if (ret) {
cscfg_list_remove_csdev(csdev);
goto reg_csdev_unlock;
}
pr_info("CSCFG registered %s", dev_name(&csdev->dev));
+reg_csdev_unlock:
mutex_unlock(&cscfg_mutex);
return ret;
+} +EXPORT_SYMBOL_GPL(cscfg_register_csdev);
+/* remove coresight device and update counts - syscfg device at 0 */ +void cscfg_unregister_csdev(struct coresight_device *csdev) +{
struct cscfg_csdev_register *curr_item, *tmp;
mutex_lock(&cscfg_mutex);
list_for_each_entry_safe(curr_item, tmp, &cscfg_data.dev_list, item) {
if (curr_item->csdev == csdev) {
list_del(&curr_item->item);
kfree(curr_item->match_info.dev_name);
kfree(curr_item);
cscfg_data.nr_csdev--;
break;
}
}
mutex_unlock(&cscfg_mutex);
+} +EXPORT_SYMBOL_GPL(cscfg_unregister_csdev);
/* Initialise system configuration management driver. */ /* only one of these */ static struct cscfg_device *cscfg_dev; diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 5a7896426eab..ecf4aac7d712 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -26,6 +26,22 @@ struct cscfg_api_data { int nr_csdev; };
+/**
- List entry for Coresight devices that are registered as supporting complex
- config operations.
- @csdev: The registered device.
- @match_info: The matching type information.
- @ops: Operations supported by the registered device.
- @item: list entry.
- */
+struct cscfg_csdev_register {
struct coresight_device *csdev;
struct cscfg_match_info match_info;
struct cscfg_csdev_feat_ops ops;
struct list_head item;
+};
/* internal core operations for cscfg */ int __init cscfg_init(void); void __exit cscfg_exit(void); @@ -33,6 +49,10 @@ void __exit cscfg_exit(void); /* syscfg external API */ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, struct cscfg_feature_desc **feat_descs); +int cscfg_register_csdev(struct coresight_device *csdev,
struct cscfg_match_info *info,
struct cscfg_csdev_feat_ops *ops);
+void cscfg_unregister_csdev(struct coresight_device *csdev);
/* system configuration device driver and API */ /** diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 7d3c87e5b97c..bade9e8ac20c 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -189,6 +189,9 @@ struct coresight_sysfs_link {
- @nr_links: number of sysfs links created to other components from this
device. These will appear in the "connections" group.
- @has_conns_grp: Have added a "connections" group for sysfs links.
- @feat_list: List of complex feature programming added to the device.
- @syscfg_list: List of system configurations added to the device.
*/
- @cfg_lock: spinlock to protect feature and config lists for this device.
struct coresight_device { struct coresight_platform_data *pdata; @@ -209,6 +212,10 @@ struct coresight_device { int nr_links; bool has_conns_grp; bool ect_enabled; /* true only if associated ect device is enabled */
/* complex config and feature lists */
struct list_head feat_list;
struct list_head syscfg_list;
I would name the above feature_csdev_list and config_csdev_list. That way it matches the declaration of cscfg_feature_csdev and cscf_config_csdev and we know exactly what is enqueued on the lists.
spinlock_t cfg_lock;
};
/*
2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
Adds a set of generic support functions that allow devices to set and save features values on the device, and enable and disable configurations.
Additional functions for other common operations including feature reset.
Signed-off-by: Mike Leach mike.leach@linaro.org --- drivers/hwtracing/coresight/Makefile | 2 +- .../hwtracing/coresight/coresight-config.c | 362 ++++++++++++++++++ .../hwtracing/coresight/coresight-config.h | 14 + .../hwtracing/coresight/coresight-syscfg.c | 4 + 4 files changed, 381 insertions(+), 1 deletion(-) create mode 100644 drivers/hwtracing/coresight/coresight-config.c
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 4ce854c434b1..daad9f103a78 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -4,7 +4,7 @@ # obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \ - coresight-sysfs.o coresight-syscfg.o + coresight-sysfs.o coresight-syscfg.o coresight-config.o obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-config.c b/drivers/hwtracing/coresight/coresight-config.c new file mode 100644 index 000000000000..d911e0f083c1 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.c @@ -0,0 +1,362 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2020 Linaro Limited. All rights reserved. + * Author: Mike Leach mike.leach@linaro.org + */ + +#include <linux/sysfs.h> +#include "coresight-config.h" +#include "coresight-priv.h" + +/* + * Write the value held in the register structure into the driver internal memory + * location. + */ +static void cscfg_set_reg(struct cscfg_reg_csdev *reg) +{ + u32 *p_val32 = (u32 *)reg->drv_store; + u32 tmp32; + + if (!(reg->value.flags & CS_CFG_REG_VAL_64BIT)) { + if (reg->value.flags & CS_CFG_REG_VAL_MASK) { + tmp32 = *p_val32; + tmp32 &= ~reg->value.mask32; + tmp32 |= reg->value.val32 & reg->value.mask32; + *p_val32 = tmp32; + } else + *p_val32 = reg->value.val32; + } else + *((u64 *)reg->drv_store) = reg->value.val64; +} + +/* + * Read the driver value into the reg if this is marked as one we want to save. + */ +static void cscfg_save_reg(struct cscfg_reg_csdev *reg) +{ + if (!(reg->value.flags & CS_CFG_REG_VAL_SAVE)) + return; + if (reg->value.flags & CS_CFG_REG_VAL_64BIT) + reg->value.val64 = *(u64 *)(reg->drv_store); + else + reg->value.val32 = *(u32 *)(reg->drv_store); +} + +static inline void cscfg_init_reg_val(struct cscfg_reg_csdev *reg, + const struct cscfg_regval *desc) +{ + reg->value.val64 = desc->val64; +} + +static inline void cscfg_init_reg_flags(struct cscfg_reg_csdev *reg, + const struct cscfg_regval *desc) +{ + reg->value.flags = desc->flags; +} + +static void cscfg_init_reg_param(struct cscfg_parameter_csdev *param, + struct cscfg_reg_csdev *reg) +{ + param->reg = reg; + param->val64 = reg->value.flags & CS_CFG_REG_VAL_64BIT; + + if (param->val64) + param->reg->value.val64 = param->current_value; + else + param->reg->value.val32 = (u32)param->current_value; +} + +/* default set - will set values without resource checking */ +static int cscfg_set_on_enable(struct cscfg_feature_csdev *feat, const bool force_set) +{ + int i; + + spin_lock(feat->csdev_spinlock); + if (feat->enabled || force_set) { + for (i = 0; i < feat->nr_regs; i++) + cscfg_set_reg(&feat->regs[i]); + } + dev_dbg(&feat->csdev->dev, "Feature %s: %s", feat->desc->name, + feat->enabled || force_set ? "Set enabled" : "Skip disabled"); + spin_unlock(feat->csdev_spinlock); + return 0; +} + +static void cscfg_save_on_disable(struct cscfg_feature_csdev *feat, const bool force_save) +{ + int i; + + spin_lock(feat->csdev_spinlock); + if (feat->enabled || force_save) { + for (i = 0; i < feat->nr_regs; i++) + cscfg_save_reg(&feat->regs[i]); + } + dev_dbg(&feat->csdev->dev, "Feature %s: %s", feat->desc->name, + feat->enabled || force_save ? "Save disabled" : "Skip disabled"); + spin_unlock(feat->csdev_spinlock); +} + +/* default reset - restore default values, disable feature */ +static void cscfg_reset_feat(struct cscfg_feature_csdev *feat) +{ + struct cscfg_reg_csdev *reg; + struct cscfg_regval *reg_desc; + struct cscfg_parameter_csdev *param; + int i; + + spin_lock(feat->csdev_spinlock); + feat->enabled = false; + + /* + * set the default values for all parameters and regs from the + * relevant static descriptors. + */ + for (i = 0; i < feat->nr_params; i++) + feat->params[i].current_value = feat->desc->params[i].value; + + for (i = 0; i < feat->nr_regs; i++) { + reg_desc = &feat->desc->regs[i]; + reg = &feat->regs[i]; + cscfg_init_reg_flags(reg, reg_desc); + + /* check if reg set from a parameter otherwise desc default */ + if (reg_desc->flags & CS_CFG_REG_VAL_PARAM) { + param = &feat->params[reg_desc->val32]; + cscfg_init_reg_param(param, reg); + } else + cscfg_init_reg_val(reg, reg_desc); + } + spin_unlock(feat->csdev_spinlock); +} + +void cscfg_set_def_ops(struct cscfg_feature_csdev *feat) +{ + feat->ops.set_on_enable = cscfg_set_on_enable; + feat->ops.save_on_disable = cscfg_save_on_disable; + feat->ops.reset = cscfg_reset_feat; +} + +int cscfg_csdev_set_enabled_feats(struct coresight_device *csdev) +{ + struct cscfg_feature_csdev *feat; + int err = 0; + + spin_lock(&csdev->cfg_lock); + if (list_empty(&csdev->feat_list)) { + spin_unlock(&csdev->cfg_lock); + return 0; + } + + list_for_each_entry(feat, &csdev->feat_list, node) { + dev_dbg(&csdev->dev, "Found feature:%s", feat->desc->name); + + if (feat->ops.set_on_enable) { + err = feat->ops.set_on_enable(feat, false); + dev_dbg(&csdev->dev, "Feature %s: %s", + feat->desc->name, err ? "Set failed" : "OK"); + if (!err) + break; + } + } + spin_unlock(&csdev->cfg_lock); + return err; +} +EXPORT_SYMBOL_GPL(cscfg_csdev_set_enabled_feats); + +void cscfg_csdev_save_enabled_feats(struct coresight_device *csdev) +{ + struct cscfg_feature_csdev *feat; + + spin_lock(&csdev->cfg_lock); + if (list_empty(&csdev->feat_list)) { + spin_unlock(&csdev->cfg_lock); + return; + } + + list_for_each_entry(feat, &csdev->feat_list, node) { + if (feat->ops.save_on_disable) + feat->ops.save_on_disable(feat, false); + } + spin_unlock(&csdev->cfg_lock); +} +EXPORT_SYMBOL_GPL(cscfg_csdev_save_enabled_feats); + +void cscfg_csdev_reset_feats(struct coresight_device *csdev) +{ + struct cscfg_feature_csdev *feat; + + spin_lock(&csdev->cfg_lock); + if (list_empty(&csdev->feat_list)) { + spin_unlock(&csdev->cfg_lock); + return; + } + + list_for_each_entry(feat, &csdev->feat_list, node) { + if (feat->ops.reset) + feat->ops.reset(feat); + } + spin_unlock(&csdev->cfg_lock); +} +EXPORT_SYMBOL_GPL(cscfg_csdev_reset_feats); + +static int cscfg_update_presets(struct cscfg_config_csdev *cfg, int preset) +{ + int i, j, line_offset = 0, val_idx = 0, max_idx; + u64 val; + struct cscfg_feature_csdev *feat; + struct cscfg_parameter_csdev *param; + const char *name; + + if (preset > cfg->desc->nr_presets) + return -EINVAL; + /* + * Go through the array of features, assigning preset values to + * feature parameters in the order they appear. + * There should be precisely the same number of preset values as the + * sum of number of parameters over all the features - but we will + * ensure there is no overrun. + */ + line_offset = (preset-1) * cfg->desc->nr_total_params; + max_idx = cfg->desc->nr_total_params; + for (i = 0; i < cfg->nr_feat; i++) { + feat = cfg->feats[i]; + if (feat->nr_params) { + spin_lock(feat->csdev_spinlock); + for (j = 0; j < feat->nr_params; j++) { + param = &feat->params[j]; + name = feat->desc->params[j].name; + val = cfg->desc->presets[line_offset + val_idx++]; + if (param->val64) { + dev_dbg(&cfg->csdev->dev, + "set param %s (%lld)", name, val); + param->reg->value.val64 = val; + } else { + param->reg->value.val32 = (u32)val; + dev_dbg(&cfg->csdev->dev, + "set param %s (%d)", name, (u32)val); + } + if (val_idx >= max_idx) + break; + } + spin_unlock(feat->csdev_spinlock); + } + + /* don't overrun the preset array line */ + if (val_idx >= max_idx) + break; + } + return 0; +} + +/* + * if we are not using a preset, then need to update the feature params + * with current values. + */ +static int cscfg_update_curr_params(struct cscfg_config_csdev *cfg) +{ + int i, j; + struct cscfg_feature_csdev *feat; + struct cscfg_parameter_csdev *param; + const char *name; + u64 val; + + for (i = 0; i < cfg->nr_feat; i++) { + feat = cfg->feats[i]; + if (feat->nr_params) { + spin_lock(feat->csdev_spinlock); + for (j = 0; j < feat->nr_params; j++) { + param = &feat->params[j]; + name = feat->desc->params[j].name; + val = param->current_value; + if (param->val64) { + dev_dbg(&cfg->csdev->dev, + "set param %s (%lld)", name, val); + param->reg->value.val64 = val; + } else { + param->reg->value.val32 = (u32)val; + dev_dbg(&cfg->csdev->dev, + "set param %s (%d)", name, (u32)val); + } + } + spin_unlock(feat->csdev_spinlock); + } + } + return 0; +} + +static int cscfg_prog_config(struct cscfg_config_csdev *cfg, bool enable) +{ + int i, err = 0; + struct cscfg_feature_csdev *feat; + struct coresight_device *csdev; + + for (i = 0; i < cfg->nr_feat; i++) { + feat = cfg->feats[i]; + csdev = feat->csdev; + dev_dbg(&csdev->dev, "cfg %s; %s feature:%s", cfg->desc->name, + enable ? "enable" : "disable", feat->desc->name); + + if (enable) { + if (feat->ops.set_on_enable) + err = feat->ops.set_on_enable(feat, true); + } else { + if (feat->ops.save_on_disable) + feat->ops.save_on_disable(feat, true); + } + if (err) + break; + } + return err; +} + +/** + * Enable configuration for the device. + * Match the config id and optionally set preset values for parameters. + * + * @csdev: coresight device to set config on. + * @cfg_id: hash id of configuration. + * @preset: preset values to use - 0 for default. + */ +int cscfg_csdev_enable_config(struct coresight_device *csdev, + unsigned long cfg_id, + int preset) +{ + struct cscfg_config_csdev *cfg; + int err = 0; + + dev_dbg(&csdev->dev, "Check for config %lx, preset %d", cfg_id, preset); + + spin_lock(&csdev->cfg_lock); + list_for_each_entry(cfg, &csdev->syscfg_list, node) { + dev_dbg(&csdev->dev, "checking %s", cfg->desc->name); + if (cfg->id_hash == cfg_id) { + if (preset) + err = cscfg_update_presets(cfg, preset); + else + err = cscfg_update_curr_params(cfg); + if (!err) + err = cscfg_prog_config(cfg, true); + if (!err) + cfg->enabled = true; + break; + } + } + spin_unlock(&csdev->cfg_lock); + return err; +} +EXPORT_SYMBOL_GPL(cscfg_csdev_enable_config); + +void cscfg_csdev_disable_config(struct coresight_device *csdev) +{ + struct cscfg_config_csdev *cfg; + + spin_lock(&csdev->cfg_lock); + list_for_each_entry(cfg, &csdev->syscfg_list, node) { + if (cfg->enabled) { + cscfg_prog_config(cfg, false); + cfg->enabled = false; + } + } + spin_unlock(&csdev->cfg_lock); +} +EXPORT_SYMBOL_GPL(cscfg_csdev_disable_config); diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 8fd7ff991ced..a3d374ebb70f 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -287,4 +287,18 @@ struct cscfg_csdev_feat_ops { struct cscfg_feature_csdev *feat); };
+/* coresight config API functions */ + +/* helper functions for feature manipulation */ +void cscfg_set_def_ops(struct cscfg_feature_csdev *feat); + +/* enable / disable features or configs on a device */ +int cscfg_csdev_set_enabled_feats(struct coresight_device *csdev); +void cscfg_csdev_save_enabled_feats(struct coresight_device *csdev); +void cscfg_csdev_reset_feats(struct coresight_device *csdev); +int cscfg_csdev_enable_config(struct coresight_device *csdev, + unsigned long cfg_id, + int preset); +void cscfg_csdev_disable_config(struct coresight_device *csdev); + #endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 53bc1d551171..98ee78e3412a 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -166,6 +166,7 @@ cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc feat->csdev = csdev; for (i = 0; i < feat->nr_params; i++) feat->params[i].feat = feat; + cscfg_set_def_ops(feat);
return feat; } @@ -195,6 +196,9 @@ static int cscfg_load_feat_csdev(struct coresight_device *csdev, list_add(&feat_csdev->node, &csdev->feat_list); spin_unlock(&csdev->cfg_lock);
+ /* force load of default parameter values into registers */ + feat_csdev->ops.reset(feat_csdev); + return 0; }
On Fri, Oct 30, 2020 at 05:56:49PM +0000, Mike Leach wrote:
Adds a set of generic support functions that allow devices to set and save features values on the device, and enable and disable configurations.
Additional functions for other common operations including feature reset.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 2 +- .../hwtracing/coresight/coresight-config.c | 362 ++++++++++++++++++ .../hwtracing/coresight/coresight-config.h | 14 + .../hwtracing/coresight/coresight-syscfg.c | 4 + 4 files changed, 381 insertions(+), 1 deletion(-) create mode 100644 drivers/hwtracing/coresight/coresight-config.c
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 4ce854c434b1..daad9f103a78 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -4,7 +4,7 @@ # obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \
coresight-sysfs.o coresight-syscfg.o
coresight-sysfs.o coresight-syscfg.o coresight-config.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-config.c b/drivers/hwtracing/coresight/coresight-config.c new file mode 100644 index 000000000000..d911e0f083c1 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.c @@ -0,0 +1,362 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright(C) 2020 Linaro Limited. All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <linux/sysfs.h> +#include "coresight-config.h" +#include "coresight-priv.h"
+/*
- Write the value held in the register structure into the driver internal memory
- location.
- */
+static void cscfg_set_reg(struct cscfg_reg_csdev *reg) +{
- u32 *p_val32 = (u32 *)reg->drv_store;
- u32 tmp32;
- if (!(reg->value.flags & CS_CFG_REG_VAL_64BIT)) {
if (reg->value.flags & CS_CFG_REG_VAL_MASK) {
tmp32 = *p_val32;
tmp32 &= ~reg->value.mask32;
tmp32 |= reg->value.val32 & reg->value.mask32;
*p_val32 = tmp32;
} else
*p_val32 = reg->value.val32;
- } else
*((u64 *)reg->drv_store) = reg->value.val64;
+}
+/*
- Read the driver value into the reg if this is marked as one we want to save.
- */
+static void cscfg_save_reg(struct cscfg_reg_csdev *reg) +{
- if (!(reg->value.flags & CS_CFG_REG_VAL_SAVE))
return;
- if (reg->value.flags & CS_CFG_REG_VAL_64BIT)
reg->value.val64 = *(u64 *)(reg->drv_store);
- else
reg->value.val32 = *(u32 *)(reg->drv_store);
+}
+static inline void cscfg_init_reg_val(struct cscfg_reg_csdev *reg,
const struct cscfg_regval *desc)
+{
- reg->value.val64 = desc->val64;
+}
+static inline void cscfg_init_reg_flags(struct cscfg_reg_csdev *reg,
const struct cscfg_regval *desc)
+{
- reg->value.flags = desc->flags;
+}
+static void cscfg_init_reg_param(struct cscfg_parameter_csdev *param,
struct cscfg_reg_csdev *reg)
+{
- param->reg = reg;
- param->val64 = reg->value.flags & CS_CFG_REG_VAL_64BIT;
- if (param->val64)
param->reg->value.val64 = param->current_value;
- else
param->reg->value.val32 = (u32)param->current_value;
+}
+/* default set - will set values without resource checking */ +static int cscfg_set_on_enable(struct cscfg_feature_csdev *feat, const bool force_set) +{
- int i;
- spin_lock(feat->csdev_spinlock);
- if (feat->enabled || force_set) {
for (i = 0; i < feat->nr_regs; i++)
cscfg_set_reg(&feat->regs[i]);
- }
- dev_dbg(&feat->csdev->dev, "Feature %s: %s", feat->desc->name,
feat->enabled || force_set ? "Set enabled" : "Skip disabled");
- spin_unlock(feat->csdev_spinlock);
- return 0;
+}
+static void cscfg_save_on_disable(struct cscfg_feature_csdev *feat, const bool force_save) +{
- int i;
- spin_lock(feat->csdev_spinlock);
- if (feat->enabled || force_save) {
for (i = 0; i < feat->nr_regs; i++)
cscfg_save_reg(&feat->regs[i]);
- }
- dev_dbg(&feat->csdev->dev, "Feature %s: %s", feat->desc->name,
feat->enabled || force_save ? "Save disabled" : "Skip disabled");
- spin_unlock(feat->csdev_spinlock);
+}
+/* default reset - restore default values, disable feature */ +static void cscfg_reset_feat(struct cscfg_feature_csdev *feat) +{
- struct cscfg_reg_csdev *reg;
- struct cscfg_regval *reg_desc;
- struct cscfg_parameter_csdev *param;
- int i;
- spin_lock(feat->csdev_spinlock);
- feat->enabled = false;
- /*
* set the default values for all parameters and regs from the
* relevant static descriptors.
*/
- for (i = 0; i < feat->nr_params; i++)
feat->params[i].current_value = feat->desc->params[i].value;
- for (i = 0; i < feat->nr_regs; i++) {
reg_desc = &feat->desc->regs[i];
reg = &feat->regs[i];
cscfg_init_reg_flags(reg, reg_desc);
/* check if reg set from a parameter otherwise desc default */
if (reg_desc->flags & CS_CFG_REG_VAL_PARAM) {
param = &feat->params[reg_desc->val32];
cscfg_init_reg_param(param, reg);
} else
cscfg_init_reg_val(reg, reg_desc);
- }
- spin_unlock(feat->csdev_spinlock);
+}
+void cscfg_set_def_ops(struct cscfg_feature_csdev *feat) +{
- feat->ops.set_on_enable = cscfg_set_on_enable;
- feat->ops.save_on_disable = cscfg_save_on_disable;
- feat->ops.reset = cscfg_reset_feat;
+}
+int cscfg_csdev_set_enabled_feats(struct coresight_device *csdev) +{
- struct cscfg_feature_csdev *feat;
- int err = 0;
- spin_lock(&csdev->cfg_lock);
- if (list_empty(&csdev->feat_list)) {
spin_unlock(&csdev->cfg_lock);
return 0;
- }
- list_for_each_entry(feat, &csdev->feat_list, node) {
dev_dbg(&csdev->dev, "Found feature:%s", feat->desc->name);
if (feat->ops.set_on_enable) {
err = feat->ops.set_on_enable(feat, false);
dev_dbg(&csdev->dev, "Feature %s: %s",
feat->desc->name, err ? "Set failed" : "OK");
if (!err)
break;
}
- }
- spin_unlock(&csdev->cfg_lock);
- return err;
+} +EXPORT_SYMBOL_GPL(cscfg_csdev_set_enabled_feats);
+void cscfg_csdev_save_enabled_feats(struct coresight_device *csdev) +{
- struct cscfg_feature_csdev *feat;
- spin_lock(&csdev->cfg_lock);
- if (list_empty(&csdev->feat_list)) {
spin_unlock(&csdev->cfg_lock);
return;
- }
- list_for_each_entry(feat, &csdev->feat_list, node) {
if (feat->ops.save_on_disable)
feat->ops.save_on_disable(feat, false);
- }
- spin_unlock(&csdev->cfg_lock);
+} +EXPORT_SYMBOL_GPL(cscfg_csdev_save_enabled_feats);
+void cscfg_csdev_reset_feats(struct coresight_device *csdev) +{
- struct cscfg_feature_csdev *feat;
- spin_lock(&csdev->cfg_lock);
- if (list_empty(&csdev->feat_list)) {
spin_unlock(&csdev->cfg_lock);
return;
- }
- list_for_each_entry(feat, &csdev->feat_list, node) {
if (feat->ops.reset)
feat->ops.reset(feat);
- }
- spin_unlock(&csdev->cfg_lock);
+} +EXPORT_SYMBOL_GPL(cscfg_csdev_reset_feats);
+static int cscfg_update_presets(struct cscfg_config_csdev *cfg, int preset) +{
- int i, j, line_offset = 0, val_idx = 0, max_idx;
- u64 val;
- struct cscfg_feature_csdev *feat;
- struct cscfg_parameter_csdev *param;
- const char *name;
int i, j, line_offset = 0, val_idx = 0, max_idx; struct cscfg_parameter_csdev *param; struct cscfg_feature_csdev *feat; const char *name; u64 val;
- if (preset > cfg->desc->nr_presets)
Extra space between if and ()
return -EINVAL;
- /*
* Go through the array of features, assigning preset values to
* feature parameters in the order they appear.
* There should be precisely the same number of preset values as the
* sum of number of parameters over all the features - but we will
* ensure there is no overrun.
*/
- line_offset = (preset-1) * cfg->desc->nr_total_params;
If I understand correctly this computation won't work in situations where there is more than one feature with varying number of parameters.
- max_idx = cfg->desc->nr_total_params;
- for (i = 0; i < cfg->nr_feat; i++) {
feat = cfg->feats[i];
if (feat->nr_params) {
if (!feat->nr_params) continue;
spin_lock(feat->csdev_spinlock);
for (j = 0; j < feat->nr_params; j++) {
param = &feat->params[j];
name = feat->desc->params[j].name;
val = cfg->desc->presets[line_offset + val_idx++];
if (param->val64) {
dev_dbg(&cfg->csdev->dev,
"set param %s (%lld)", name, val);
param->reg->value.val64 = val;
} else {
param->reg->value.val32 = (u32)val;
dev_dbg(&cfg->csdev->dev,
"set param %s (%d)", name, (u32)val);
}
if (val_idx >= max_idx)
break;
}
spin_unlock(feat->csdev_spinlock);
}
/* don't overrun the preset array line */
if (val_idx >= max_idx)
break;
- }
- return 0;
+}
+/*
- if we are not using a preset, then need to update the feature params
- with current values.
- */
+static int cscfg_update_curr_params(struct cscfg_config_csdev *cfg) +{
- int i, j;
- struct cscfg_feature_csdev *feat;
- struct cscfg_parameter_csdev *param;
- const char *name;
- u64 val;
- for (i = 0; i < cfg->nr_feat; i++) {
feat = cfg->feats[i];
if (feat->nr_params) {
if (!feat->nr_params) continue;
spin_lock(feat->csdev_spinlock);
Please add a comment on why taking the spinlock is needed, i.e what kind of action would corrupt the data.
for (j = 0; j < feat->nr_params; j++) {
param = &feat->params[j];
name = feat->desc->params[j].name;
val = param->current_value;
if (param->val64) {
dev_dbg(&cfg->csdev->dev,
"set param %s (%lld)", name, val);
param->reg->value.val64 = val;
} else {
param->reg->value.val32 = (u32)val;
dev_dbg(&cfg->csdev->dev,
"set param %s (%d)", name, (u32)val);
}
}
spin_unlock(feat->csdev_spinlock);
}
- }
- return 0;
+}
+static int cscfg_prog_config(struct cscfg_config_csdev *cfg, bool enable) +{
- int i, err = 0;
- struct cscfg_feature_csdev *feat;
- struct coresight_device *csdev;
- for (i = 0; i < cfg->nr_feat; i++) {
feat = cfg->feats[i];
csdev = feat->csdev;
dev_dbg(&csdev->dev, "cfg %s; %s feature:%s", cfg->desc->name,
enable ? "enable" : "disable", feat->desc->name);
if (enable) {
if (feat->ops.set_on_enable)
err = feat->ops.set_on_enable(feat, true);
} else {
if (feat->ops.save_on_disable)
feat->ops.save_on_disable(feat, true);
}
if (err)
break;
- }
- return err;
+}
+/**
- Enable configuration for the device.
- Match the config id and optionally set preset values for parameters.
- @csdev: coresight device to set config on.
- @cfg_id: hash id of configuration.
- @preset: preset values to use - 0 for default.
- */
+int cscfg_csdev_enable_config(struct coresight_device *csdev,
unsigned long cfg_id,
int preset)
Please avoid stacking when possible. Here @preset fits on the previous line. The same applies for the function declaration in coresigt-config.h
I will continue with this patch tomorrow.
Thanks, Mathieu
+{
- struct cscfg_config_csdev *cfg;
- int err = 0;
- dev_dbg(&csdev->dev, "Check for config %lx, preset %d", cfg_id, preset);
- spin_lock(&csdev->cfg_lock);
- list_for_each_entry(cfg, &csdev->syscfg_list, node) {
dev_dbg(&csdev->dev, "checking %s", cfg->desc->name);
if (cfg->id_hash == cfg_id) {
if (preset)
err = cscfg_update_presets(cfg, preset);
else
err = cscfg_update_curr_params(cfg);
if (!err)
err = cscfg_prog_config(cfg, true);
if (!err)
cfg->enabled = true;
break;
}
- }
- spin_unlock(&csdev->cfg_lock);
- return err;
+} +EXPORT_SYMBOL_GPL(cscfg_csdev_enable_config);
+void cscfg_csdev_disable_config(struct coresight_device *csdev) +{
- struct cscfg_config_csdev *cfg;
- spin_lock(&csdev->cfg_lock);
- list_for_each_entry(cfg, &csdev->syscfg_list, node) {
if (cfg->enabled) {
cscfg_prog_config(cfg, false);
cfg->enabled = false;
}
- }
- spin_unlock(&csdev->cfg_lock);
+} +EXPORT_SYMBOL_GPL(cscfg_csdev_disable_config); diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 8fd7ff991ced..a3d374ebb70f 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -287,4 +287,18 @@ struct cscfg_csdev_feat_ops { struct cscfg_feature_csdev *feat); }; +/* coresight config API functions */
+/* helper functions for feature manipulation */ +void cscfg_set_def_ops(struct cscfg_feature_csdev *feat);
+/* enable / disable features or configs on a device */ +int cscfg_csdev_set_enabled_feats(struct coresight_device *csdev); +void cscfg_csdev_save_enabled_feats(struct coresight_device *csdev); +void cscfg_csdev_reset_feats(struct coresight_device *csdev); +int cscfg_csdev_enable_config(struct coresight_device *csdev,
unsigned long cfg_id,
int preset);
+void cscfg_csdev_disable_config(struct coresight_device *csdev);
#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 53bc1d551171..98ee78e3412a 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -166,6 +166,7 @@ cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc feat->csdev = csdev; for (i = 0; i < feat->nr_params; i++) feat->params[i].feat = feat;
- cscfg_set_def_ops(feat);
return feat; } @@ -195,6 +196,9 @@ static int cscfg_load_feat_csdev(struct coresight_device *csdev, list_add(&feat_csdev->node, &csdev->feat_list); spin_unlock(&csdev->cfg_lock);
- /* force load of default parameter values into registers */
- feat_csdev->ops.reset(feat_csdev);
- return 0;
} -- 2.17.1
Hi Mike,
On Fri, Oct 30, 2020 at 05:56:49PM +0000, Mike Leach wrote:
Adds a set of generic support functions that allow devices to set and save features values on the device, and enable and disable configurations.
Additional functions for other common operations including feature reset.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 2 +- .../hwtracing/coresight/coresight-config.c | 362 ++++++++++++++++++ .../hwtracing/coresight/coresight-config.h | 14 + .../hwtracing/coresight/coresight-syscfg.c | 4 + 4 files changed, 381 insertions(+), 1 deletion(-) create mode 100644 drivers/hwtracing/coresight/coresight-config.c
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 4ce854c434b1..daad9f103a78 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -4,7 +4,7 @@ # obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \
coresight-sysfs.o coresight-syscfg.o
coresight-sysfs.o coresight-syscfg.o coresight-config.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-config.c b/drivers/hwtracing/coresight/coresight-config.c new file mode 100644 index 000000000000..d911e0f083c1 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.c @@ -0,0 +1,362 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright(C) 2020 Linaro Limited. All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <linux/sysfs.h> +#include "coresight-config.h" +#include "coresight-priv.h"
+/*
- Write the value held in the register structure into the driver internal memory
- location.
- */
+static void cscfg_set_reg(struct cscfg_reg_csdev *reg) +{
- u32 *p_val32 = (u32 *)reg->drv_store;
- u32 tmp32;
- if (!(reg->value.flags & CS_CFG_REG_VAL_64BIT)) {
if (reg->value.flags & CS_CFG_REG_VAL_MASK) {
tmp32 = *p_val32;
tmp32 &= ~reg->value.mask32;
tmp32 |= reg->value.val32 & reg->value.mask32;
*p_val32 = tmp32;
} else
*p_val32 = reg->value.val32;
- } else
*((u64 *)reg->drv_store) = reg->value.val64;
+}
+/*
- Read the driver value into the reg if this is marked as one we want to save.
- */
+static void cscfg_save_reg(struct cscfg_reg_csdev *reg) +{
- if (!(reg->value.flags & CS_CFG_REG_VAL_SAVE))
return;
- if (reg->value.flags & CS_CFG_REG_VAL_64BIT)
reg->value.val64 = *(u64 *)(reg->drv_store);
- else
reg->value.val32 = *(u32 *)(reg->drv_store);
+}
+static inline void cscfg_init_reg_val(struct cscfg_reg_csdev *reg,
const struct cscfg_regval *desc)
+{
- reg->value.val64 = desc->val64;
+}
+static inline void cscfg_init_reg_flags(struct cscfg_reg_csdev *reg,
const struct cscfg_regval *desc)
+{
- reg->value.flags = desc->flags;
+}
+static void cscfg_init_reg_param(struct cscfg_parameter_csdev *param,
struct cscfg_reg_csdev *reg)
+{
- param->reg = reg;
- param->val64 = reg->value.flags & CS_CFG_REG_VAL_64BIT;
- if (param->val64)
param->reg->value.val64 = param->current_value;
- else
param->reg->value.val32 = (u32)param->current_value;
+}
+/* default set - will set values without resource checking */ +static int cscfg_set_on_enable(struct cscfg_feature_csdev *feat, const bool force_set) +{
Please add a description of what @force_set is used for and why we need it. Same for @force_save in cscfg_save_on_disable() below.
- int i;
- spin_lock(feat->csdev_spinlock);
- if (feat->enabled || force_set) {
for (i = 0; i < feat->nr_regs; i++)
cscfg_set_reg(&feat->regs[i]);
- }
- dev_dbg(&feat->csdev->dev, "Feature %s: %s", feat->desc->name,
feat->enabled || force_set ? "Set enabled" : "Skip disabled");
- spin_unlock(feat->csdev_spinlock);
- return 0;
+}
+static void cscfg_save_on_disable(struct cscfg_feature_csdev *feat, const bool force_save) +{
- int i;
- spin_lock(feat->csdev_spinlock);
- if (feat->enabled || force_save) {
for (i = 0; i < feat->nr_regs; i++)
cscfg_save_reg(&feat->regs[i]);
- }
- dev_dbg(&feat->csdev->dev, "Feature %s: %s", feat->desc->name,
feat->enabled || force_save ? "Save disabled" : "Skip disabled");
- spin_unlock(feat->csdev_spinlock);
+}
+/* default reset - restore default values, disable feature */ +static void cscfg_reset_feat(struct cscfg_feature_csdev *feat) +{
- struct cscfg_reg_csdev *reg;
struct cscfg_reg_csdev *reg_csdev;
- struct cscfg_regval *reg_desc;
Renaming struct cscfg_regval to cscfg_reg_desc would be consistent with what is done for parameters, features and configurations. The above would then become:
struct cscfg_reg_desc *reg_desc;
And that is very easy to remember when reading the code. I suggest that all instances of these structures (thoughout the patchset) follow this convention.
- struct cscfg_parameter_csdev *param;
Here too, and throughout:
struct cscfg_parameter_csdev *param_csdev;
- int i;
- spin_lock(feat->csdev_spinlock);
- feat->enabled = false;
- /*
* set the default values for all parameters and regs from the
* relevant static descriptors.
*/
- for (i = 0; i < feat->nr_params; i++)
feat->params[i].current_value = feat->desc->params[i].value;
- for (i = 0; i < feat->nr_regs; i++) {
reg_desc = &feat->desc->regs[i];
reg = &feat->regs[i];
cscfg_init_reg_flags(reg, reg_desc);
I would just initialise the flag, no need for another function.
/* check if reg set from a parameter otherwise desc default */
if (reg_desc->flags & CS_CFG_REG_VAL_PARAM) {
param = &feat->params[reg_desc->val32];
There is something wrong with reg_desc->val32 as an array index in the above. I'm surprised it did blow up on you yet. Moreover this is another instance where having multiple features, each with their own number of parameters, will be complex to work with.
cscfg_init_reg_param(param, reg);
} else
cscfg_init_reg_val(reg, reg_desc);
Here too I wouldn't bother with a function.
- }
- spin_unlock(feat->csdev_spinlock);
+}
+void cscfg_set_def_ops(struct cscfg_feature_csdev *feat) +{
- feat->ops.set_on_enable = cscfg_set_on_enable;
- feat->ops.save_on_disable = cscfg_save_on_disable;
- feat->ops.reset = cscfg_reset_feat;
+}
When do you expect these to change, at least for this set?
For the time being I am done with this patch.
Thanks, Mathieu
+int cscfg_csdev_set_enabled_feats(struct coresight_device *csdev) +{
- struct cscfg_feature_csdev *feat;
- int err = 0;
- spin_lock(&csdev->cfg_lock);
- if (list_empty(&csdev->feat_list)) {
spin_unlock(&csdev->cfg_lock);
return 0;
- }
- list_for_each_entry(feat, &csdev->feat_list, node) {
dev_dbg(&csdev->dev, "Found feature:%s", feat->desc->name);
if (feat->ops.set_on_enable) {
err = feat->ops.set_on_enable(feat, false);
dev_dbg(&csdev->dev, "Feature %s: %s",
feat->desc->name, err ? "Set failed" : "OK");
if (!err)
break;
}
- }
- spin_unlock(&csdev->cfg_lock);
- return err;
+} +EXPORT_SYMBOL_GPL(cscfg_csdev_set_enabled_feats);
+void cscfg_csdev_save_enabled_feats(struct coresight_device *csdev) +{
- struct cscfg_feature_csdev *feat;
- spin_lock(&csdev->cfg_lock);
- if (list_empty(&csdev->feat_list)) {
spin_unlock(&csdev->cfg_lock);
return;
- }
- list_for_each_entry(feat, &csdev->feat_list, node) {
if (feat->ops.save_on_disable)
feat->ops.save_on_disable(feat, false);
- }
- spin_unlock(&csdev->cfg_lock);
+} +EXPORT_SYMBOL_GPL(cscfg_csdev_save_enabled_feats);
+void cscfg_csdev_reset_feats(struct coresight_device *csdev) +{
- struct cscfg_feature_csdev *feat;
- spin_lock(&csdev->cfg_lock);
- if (list_empty(&csdev->feat_list)) {
spin_unlock(&csdev->cfg_lock);
return;
- }
- list_for_each_entry(feat, &csdev->feat_list, node) {
if (feat->ops.reset)
feat->ops.reset(feat);
- }
- spin_unlock(&csdev->cfg_lock);
+} +EXPORT_SYMBOL_GPL(cscfg_csdev_reset_feats);
+static int cscfg_update_presets(struct cscfg_config_csdev *cfg, int preset) +{
- int i, j, line_offset = 0, val_idx = 0, max_idx;
- u64 val;
- struct cscfg_feature_csdev *feat;
- struct cscfg_parameter_csdev *param;
- const char *name;
- if (preset > cfg->desc->nr_presets)
return -EINVAL;
- /*
* Go through the array of features, assigning preset values to
* feature parameters in the order they appear.
* There should be precisely the same number of preset values as the
* sum of number of parameters over all the features - but we will
* ensure there is no overrun.
*/
- line_offset = (preset-1) * cfg->desc->nr_total_params;
- max_idx = cfg->desc->nr_total_params;
- for (i = 0; i < cfg->nr_feat; i++) {
feat = cfg->feats[i];
if (feat->nr_params) {
spin_lock(feat->csdev_spinlock);
for (j = 0; j < feat->nr_params; j++) {
param = &feat->params[j];
name = feat->desc->params[j].name;
val = cfg->desc->presets[line_offset + val_idx++];
if (param->val64) {
dev_dbg(&cfg->csdev->dev,
"set param %s (%lld)", name, val);
param->reg->value.val64 = val;
} else {
param->reg->value.val32 = (u32)val;
dev_dbg(&cfg->csdev->dev,
"set param %s (%d)", name, (u32)val);
}
if (val_idx >= max_idx)
break;
}
spin_unlock(feat->csdev_spinlock);
}
/* don't overrun the preset array line */
if (val_idx >= max_idx)
break;
- }
- return 0;
+}
+/*
- if we are not using a preset, then need to update the feature params
- with current values.
- */
+static int cscfg_update_curr_params(struct cscfg_config_csdev *cfg) +{
- int i, j;
- struct cscfg_feature_csdev *feat;
- struct cscfg_parameter_csdev *param;
- const char *name;
- u64 val;
- for (i = 0; i < cfg->nr_feat; i++) {
feat = cfg->feats[i];
if (feat->nr_params) {
spin_lock(feat->csdev_spinlock);
for (j = 0; j < feat->nr_params; j++) {
param = &feat->params[j];
name = feat->desc->params[j].name;
val = param->current_value;
if (param->val64) {
dev_dbg(&cfg->csdev->dev,
"set param %s (%lld)", name, val);
param->reg->value.val64 = val;
} else {
param->reg->value.val32 = (u32)val;
dev_dbg(&cfg->csdev->dev,
"set param %s (%d)", name, (u32)val);
}
}
spin_unlock(feat->csdev_spinlock);
}
- }
- return 0;
+}
+static int cscfg_prog_config(struct cscfg_config_csdev *cfg, bool enable) +{
- int i, err = 0;
- struct cscfg_feature_csdev *feat;
- struct coresight_device *csdev;
- for (i = 0; i < cfg->nr_feat; i++) {
feat = cfg->feats[i];
csdev = feat->csdev;
dev_dbg(&csdev->dev, "cfg %s; %s feature:%s", cfg->desc->name,
enable ? "enable" : "disable", feat->desc->name);
if (enable) {
if (feat->ops.set_on_enable)
err = feat->ops.set_on_enable(feat, true);
} else {
if (feat->ops.save_on_disable)
feat->ops.save_on_disable(feat, true);
}
if (err)
break;
- }
- return err;
+}
+/**
- Enable configuration for the device.
- Match the config id and optionally set preset values for parameters.
- @csdev: coresight device to set config on.
- @cfg_id: hash id of configuration.
- @preset: preset values to use - 0 for default.
- */
+int cscfg_csdev_enable_config(struct coresight_device *csdev,
unsigned long cfg_id,
int preset)
+{
- struct cscfg_config_csdev *cfg;
- int err = 0;
- dev_dbg(&csdev->dev, "Check for config %lx, preset %d", cfg_id, preset);
- spin_lock(&csdev->cfg_lock);
- list_for_each_entry(cfg, &csdev->syscfg_list, node) {
dev_dbg(&csdev->dev, "checking %s", cfg->desc->name);
if (cfg->id_hash == cfg_id) {
if (preset)
err = cscfg_update_presets(cfg, preset);
else
err = cscfg_update_curr_params(cfg);
if (!err)
err = cscfg_prog_config(cfg, true);
if (!err)
cfg->enabled = true;
break;
}
- }
- spin_unlock(&csdev->cfg_lock);
- return err;
+} +EXPORT_SYMBOL_GPL(cscfg_csdev_enable_config);
+void cscfg_csdev_disable_config(struct coresight_device *csdev) +{
- struct cscfg_config_csdev *cfg;
- spin_lock(&csdev->cfg_lock);
- list_for_each_entry(cfg, &csdev->syscfg_list, node) {
if (cfg->enabled) {
cscfg_prog_config(cfg, false);
cfg->enabled = false;
}
- }
- spin_unlock(&csdev->cfg_lock);
+} +EXPORT_SYMBOL_GPL(cscfg_csdev_disable_config); diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 8fd7ff991ced..a3d374ebb70f 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -287,4 +287,18 @@ struct cscfg_csdev_feat_ops { struct cscfg_feature_csdev *feat); }; +/* coresight config API functions */
+/* helper functions for feature manipulation */ +void cscfg_set_def_ops(struct cscfg_feature_csdev *feat);
+/* enable / disable features or configs on a device */ +int cscfg_csdev_set_enabled_feats(struct coresight_device *csdev); +void cscfg_csdev_save_enabled_feats(struct coresight_device *csdev); +void cscfg_csdev_reset_feats(struct coresight_device *csdev); +int cscfg_csdev_enable_config(struct coresight_device *csdev,
unsigned long cfg_id,
int preset);
+void cscfg_csdev_disable_config(struct coresight_device *csdev);
#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 53bc1d551171..98ee78e3412a 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -166,6 +166,7 @@ cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc feat->csdev = csdev; for (i = 0; i < feat->nr_params; i++) feat->params[i].feat = feat;
- cscfg_set_def_ops(feat);
return feat; } @@ -195,6 +196,9 @@ static int cscfg_load_feat_csdev(struct coresight_device *csdev, list_add(&feat_csdev->node, &csdev->feat_list); spin_unlock(&csdev->cfg_lock);
- /* force load of default parameter values into registers */
- feat_csdev->ops.reset(feat_csdev);
- return 0;
} -- 2.17.1
Hi Mathieu,
From the first set of comments
"
line_offset = (preset-1) * cfg->desc->nr_total_params;
If I understand correctly this computation won't work in situations where there is more than one feature with varying number of parameters. "
This is correct - desc->nr_total_params is defined as the sum of all feat->nr_params for the config. Hence this is the length of a row in the preset array.
On Thu, 19 Nov 2020 at 22:29, Mathieu Poirier mathieu.poirier@linaro.org wrote:
Hi Mike,
On Fri, Oct 30, 2020 at 05:56:49PM +0000, Mike Leach wrote:
Adds a set of generic support functions that allow devices to set and save features values on the device, and enable and disable configurations.
Additional functions for other common operations including feature reset.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 2 +- .../hwtracing/coresight/coresight-config.c | 362 ++++++++++++++++++ .../hwtracing/coresight/coresight-config.h | 14 + .../hwtracing/coresight/coresight-syscfg.c | 4 + 4 files changed, 381 insertions(+), 1 deletion(-) create mode 100644 drivers/hwtracing/coresight/coresight-config.c
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 4ce854c434b1..daad9f103a78 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -4,7 +4,7 @@ # obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \
coresight-sysfs.o coresight-syscfg.o
coresight-sysfs.o coresight-syscfg.o coresight-config.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-config.c b/drivers/hwtracing/coresight/coresight-config.c new file mode 100644 index 000000000000..d911e0f083c1 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.c @@ -0,0 +1,362 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright(C) 2020 Linaro Limited. All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <linux/sysfs.h> +#include "coresight-config.h" +#include "coresight-priv.h"
+/*
- Write the value held in the register structure into the driver internal memory
- location.
- */
+static void cscfg_set_reg(struct cscfg_reg_csdev *reg) +{
u32 *p_val32 = (u32 *)reg->drv_store;
u32 tmp32;
if (!(reg->value.flags & CS_CFG_REG_VAL_64BIT)) {
if (reg->value.flags & CS_CFG_REG_VAL_MASK) {
tmp32 = *p_val32;
tmp32 &= ~reg->value.mask32;
tmp32 |= reg->value.val32 & reg->value.mask32;
*p_val32 = tmp32;
} else
*p_val32 = reg->value.val32;
} else
*((u64 *)reg->drv_store) = reg->value.val64;
+}
+/*
- Read the driver value into the reg if this is marked as one we want to save.
- */
+static void cscfg_save_reg(struct cscfg_reg_csdev *reg) +{
if (!(reg->value.flags & CS_CFG_REG_VAL_SAVE))
return;
if (reg->value.flags & CS_CFG_REG_VAL_64BIT)
reg->value.val64 = *(u64 *)(reg->drv_store);
else
reg->value.val32 = *(u32 *)(reg->drv_store);
+}
+static inline void cscfg_init_reg_val(struct cscfg_reg_csdev *reg,
const struct cscfg_regval *desc)
+{
reg->value.val64 = desc->val64;
+}
+static inline void cscfg_init_reg_flags(struct cscfg_reg_csdev *reg,
const struct cscfg_regval *desc)
+{
reg->value.flags = desc->flags;
+}
+static void cscfg_init_reg_param(struct cscfg_parameter_csdev *param,
struct cscfg_reg_csdev *reg)
+{
param->reg = reg;
param->val64 = reg->value.flags & CS_CFG_REG_VAL_64BIT;
if (param->val64)
param->reg->value.val64 = param->current_value;
else
param->reg->value.val32 = (u32)param->current_value;
+}
+/* default set - will set values without resource checking */ +static int cscfg_set_on_enable(struct cscfg_feature_csdev *feat, const bool force_set) +{
Please add a description of what @force_set is used for and why we need it. Same for @force_save in cscfg_save_on_disable() below.
This is changing considerably. I was originally trying to account for features being enabled independently from configs - in a similar way we can use perf and sysfs independently - but this is unneeded and too complicated. Moving forwards enabling a config, enables dependent features - so the @force thing is dropped for an updated mechanism.
int i;
spin_lock(feat->csdev_spinlock);
if (feat->enabled || force_set) {
for (i = 0; i < feat->nr_regs; i++)
cscfg_set_reg(&feat->regs[i]);
}
dev_dbg(&feat->csdev->dev, "Feature %s: %s", feat->desc->name,
feat->enabled || force_set ? "Set enabled" : "Skip disabled");
spin_unlock(feat->csdev_spinlock);
return 0;
+}
+static void cscfg_save_on_disable(struct cscfg_feature_csdev *feat, const bool force_save) +{
int i;
spin_lock(feat->csdev_spinlock);
if (feat->enabled || force_save) {
for (i = 0; i < feat->nr_regs; i++)
cscfg_save_reg(&feat->regs[i]);
}
dev_dbg(&feat->csdev->dev, "Feature %s: %s", feat->desc->name,
feat->enabled || force_save ? "Save disabled" : "Skip disabled");
spin_unlock(feat->csdev_spinlock);
+}
+/* default reset - restore default values, disable feature */ +static void cscfg_reset_feat(struct cscfg_feature_csdev *feat) +{
struct cscfg_reg_csdev *reg;
struct cscfg_reg_csdev *reg_csdev;
struct cscfg_regval *reg_desc;
Renaming struct cscfg_regval to cscfg_reg_desc would be consistent with what is done for parameters, features and configurations. The above would then become:
struct cscfg_reg_desc *reg_desc;
And that is very easy to remember when reading the code. I suggest that all instances of these structures (thoughout the patchset) follow this convention.
struct cscfg_parameter_csdev *param;
Here too, and throughout:
struct cscfg_parameter_csdev *param_csdev;
Agreed - convention works well.]
int i;
spin_lock(feat->csdev_spinlock);
feat->enabled = false;
/*
* set the default values for all parameters and regs from the
* relevant static descriptors.
*/
for (i = 0; i < feat->nr_params; i++)
feat->params[i].current_value = feat->desc->params[i].value;
for (i = 0; i < feat->nr_regs; i++) {
reg_desc = &feat->desc->regs[i];
reg = &feat->regs[i];
cscfg_init_reg_flags(reg, reg_desc);
I would just initialise the flag, no need for another function.
/* check if reg set from a parameter otherwise desc default */
if (reg_desc->flags & CS_CFG_REG_VAL_PARAM) {
param = &feat->params[reg_desc->val32];
There is something wrong with reg_desc->val32 as an array index in the above. I'm surprised it did blow up on you yet. Moreover this is another instance where having multiple features, each with their own number of parameters, will be complex to work with.
If the regcal_desc defines the value as a parameter index, then this is fine. However, there is a case for range validation.
cscfg_init_reg_param(param, reg);
} else
cscfg_init_reg_val(reg, reg_desc);
Here too I wouldn't bother with a function.
I was trying for better readability - plus the init of reg can depend on flags in reg_desc.
}
spin_unlock(feat->csdev_spinlock);
+}
+void cscfg_set_def_ops(struct cscfg_feature_csdev *feat) +{
feat->ops.set_on_enable = cscfg_set_on_enable;
feat->ops.save_on_disable = cscfg_save_on_disable;
feat->ops.reset = cscfg_reset_feat;
+}
When do you expect these to change, at least for this set?
Nowhere in this set, but as support is expanded, device specific elements will appear in set on enable - specifically in ETM, where the register is defined as a resource e.g. counter N. so the ETMv4 driver will override this to select an appropriate counter. Thus the feature says "I want this to be a counter resource", and on set, the ETM driver will pick an unused counter. This is for the follow up sets, but I wanted to establish the API here.
Thanks
Mike
For the time being I am done with this patch.
Thanks, Mathieu
+int cscfg_csdev_set_enabled_feats(struct coresight_device *csdev) +{
struct cscfg_feature_csdev *feat;
int err = 0;
spin_lock(&csdev->cfg_lock);
if (list_empty(&csdev->feat_list)) {
spin_unlock(&csdev->cfg_lock);
return 0;
}
list_for_each_entry(feat, &csdev->feat_list, node) {
dev_dbg(&csdev->dev, "Found feature:%s", feat->desc->name);
if (feat->ops.set_on_enable) {
err = feat->ops.set_on_enable(feat, false);
dev_dbg(&csdev->dev, "Feature %s: %s",
feat->desc->name, err ? "Set failed" : "OK");
if (!err)
break;
}
}
spin_unlock(&csdev->cfg_lock);
return err;
+} +EXPORT_SYMBOL_GPL(cscfg_csdev_set_enabled_feats);
+void cscfg_csdev_save_enabled_feats(struct coresight_device *csdev) +{
struct cscfg_feature_csdev *feat;
spin_lock(&csdev->cfg_lock);
if (list_empty(&csdev->feat_list)) {
spin_unlock(&csdev->cfg_lock);
return;
}
list_for_each_entry(feat, &csdev->feat_list, node) {
if (feat->ops.save_on_disable)
feat->ops.save_on_disable(feat, false);
}
spin_unlock(&csdev->cfg_lock);
+} +EXPORT_SYMBOL_GPL(cscfg_csdev_save_enabled_feats);
+void cscfg_csdev_reset_feats(struct coresight_device *csdev) +{
struct cscfg_feature_csdev *feat;
spin_lock(&csdev->cfg_lock);
if (list_empty(&csdev->feat_list)) {
spin_unlock(&csdev->cfg_lock);
return;
}
list_for_each_entry(feat, &csdev->feat_list, node) {
if (feat->ops.reset)
feat->ops.reset(feat);
}
spin_unlock(&csdev->cfg_lock);
+} +EXPORT_SYMBOL_GPL(cscfg_csdev_reset_feats);
+static int cscfg_update_presets(struct cscfg_config_csdev *cfg, int preset) +{
int i, j, line_offset = 0, val_idx = 0, max_idx;
u64 val;
struct cscfg_feature_csdev *feat;
struct cscfg_parameter_csdev *param;
const char *name;
if (preset > cfg->desc->nr_presets)
return -EINVAL;
/*
* Go through the array of features, assigning preset values to
* feature parameters in the order they appear.
* There should be precisely the same number of preset values as the
* sum of number of parameters over all the features - but we will
* ensure there is no overrun.
*/
line_offset = (preset-1) * cfg->desc->nr_total_params;
max_idx = cfg->desc->nr_total_params;
for (i = 0; i < cfg->nr_feat; i++) {
feat = cfg->feats[i];
if (feat->nr_params) {
spin_lock(feat->csdev_spinlock);
for (j = 0; j < feat->nr_params; j++) {
param = &feat->params[j];
name = feat->desc->params[j].name;
val = cfg->desc->presets[line_offset + val_idx++];
if (param->val64) {
dev_dbg(&cfg->csdev->dev,
"set param %s (%lld)", name, val);
param->reg->value.val64 = val;
} else {
param->reg->value.val32 = (u32)val;
dev_dbg(&cfg->csdev->dev,
"set param %s (%d)", name, (u32)val);
}
if (val_idx >= max_idx)
break;
}
spin_unlock(feat->csdev_spinlock);
}
/* don't overrun the preset array line */
if (val_idx >= max_idx)
break;
}
return 0;
+}
+/*
- if we are not using a preset, then need to update the feature params
- with current values.
- */
+static int cscfg_update_curr_params(struct cscfg_config_csdev *cfg) +{
int i, j;
struct cscfg_feature_csdev *feat;
struct cscfg_parameter_csdev *param;
const char *name;
u64 val;
for (i = 0; i < cfg->nr_feat; i++) {
feat = cfg->feats[i];
if (feat->nr_params) {
spin_lock(feat->csdev_spinlock);
for (j = 0; j < feat->nr_params; j++) {
param = &feat->params[j];
name = feat->desc->params[j].name;
val = param->current_value;
if (param->val64) {
dev_dbg(&cfg->csdev->dev,
"set param %s (%lld)", name, val);
param->reg->value.val64 = val;
} else {
param->reg->value.val32 = (u32)val;
dev_dbg(&cfg->csdev->dev,
"set param %s (%d)", name, (u32)val);
}
}
spin_unlock(feat->csdev_spinlock);
}
}
return 0;
+}
+static int cscfg_prog_config(struct cscfg_config_csdev *cfg, bool enable) +{
int i, err = 0;
struct cscfg_feature_csdev *feat;
struct coresight_device *csdev;
for (i = 0; i < cfg->nr_feat; i++) {
feat = cfg->feats[i];
csdev = feat->csdev;
dev_dbg(&csdev->dev, "cfg %s; %s feature:%s", cfg->desc->name,
enable ? "enable" : "disable", feat->desc->name);
if (enable) {
if (feat->ops.set_on_enable)
err = feat->ops.set_on_enable(feat, true);
} else {
if (feat->ops.save_on_disable)
feat->ops.save_on_disable(feat, true);
}
if (err)
break;
}
return err;
+}
+/**
- Enable configuration for the device.
- Match the config id and optionally set preset values for parameters.
- @csdev: coresight device to set config on.
- @cfg_id: hash id of configuration.
- @preset: preset values to use - 0 for default.
- */
+int cscfg_csdev_enable_config(struct coresight_device *csdev,
unsigned long cfg_id,
int preset)
+{
struct cscfg_config_csdev *cfg;
int err = 0;
dev_dbg(&csdev->dev, "Check for config %lx, preset %d", cfg_id, preset);
spin_lock(&csdev->cfg_lock);
list_for_each_entry(cfg, &csdev->syscfg_list, node) {
dev_dbg(&csdev->dev, "checking %s", cfg->desc->name);
if (cfg->id_hash == cfg_id) {
if (preset)
err = cscfg_update_presets(cfg, preset);
else
err = cscfg_update_curr_params(cfg);
if (!err)
err = cscfg_prog_config(cfg, true);
if (!err)
cfg->enabled = true;
break;
}
}
spin_unlock(&csdev->cfg_lock);
return err;
+} +EXPORT_SYMBOL_GPL(cscfg_csdev_enable_config);
+void cscfg_csdev_disable_config(struct coresight_device *csdev) +{
struct cscfg_config_csdev *cfg;
spin_lock(&csdev->cfg_lock);
list_for_each_entry(cfg, &csdev->syscfg_list, node) {
if (cfg->enabled) {
cscfg_prog_config(cfg, false);
cfg->enabled = false;
}
}
spin_unlock(&csdev->cfg_lock);
+} +EXPORT_SYMBOL_GPL(cscfg_csdev_disable_config); diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 8fd7ff991ced..a3d374ebb70f 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -287,4 +287,18 @@ struct cscfg_csdev_feat_ops { struct cscfg_feature_csdev *feat); };
+/* coresight config API functions */
+/* helper functions for feature manipulation */ +void cscfg_set_def_ops(struct cscfg_feature_csdev *feat);
+/* enable / disable features or configs on a device */ +int cscfg_csdev_set_enabled_feats(struct coresight_device *csdev); +void cscfg_csdev_save_enabled_feats(struct coresight_device *csdev); +void cscfg_csdev_reset_feats(struct coresight_device *csdev); +int cscfg_csdev_enable_config(struct coresight_device *csdev,
unsigned long cfg_id,
int preset);
+void cscfg_csdev_disable_config(struct coresight_device *csdev);
#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 53bc1d551171..98ee78e3412a 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -166,6 +166,7 @@ cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc feat->csdev = csdev; for (i = 0; i < feat->nr_params; i++) feat->params[i].feat = feat;
cscfg_set_def_ops(feat); return feat;
} @@ -195,6 +196,9 @@ static int cscfg_load_feat_csdev(struct coresight_device *csdev, list_add(&feat_csdev->node, &csdev->feat_list); spin_unlock(&csdev->cfg_lock);
/* force load of default parameter values into registers */
feat_csdev->ops.reset(feat_csdev);
return 0;
}
-- 2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
Loaded coresight configurations are registered in the cs_etm\cs_config sub directory. This extends the etm-perf code to handle these registrations, and the cs_syscfg driver to perform the registration on load.
Signed-off-by: Mike Leach mike.leach@linaro.org --- .../hwtracing/coresight/coresight-config.h | 5 +- .../hwtracing/coresight/coresight-etm-perf.c | 164 +++++++++++++++--- .../hwtracing/coresight/coresight-etm-perf.h | 8 + .../hwtracing/coresight/coresight-syscfg.c | 23 ++- 4 files changed, 172 insertions(+), 28 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index a3d374ebb70f..372f29a59688 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -154,7 +154,8 @@ struct cscfg_config_feat_ref { * @nr_presets: Number of sets of presets supplied by this configuration. * @nr_total_params: Sum of all parameters declared by used features * @presets: Array of preset values. - * + * @id_ea: Extended attribute for perf configid value + * @event_ea: Extended attribute for perf event value */ struct cscfg_config_desc { const char *name; @@ -165,6 +166,8 @@ struct cscfg_config_desc { int nr_presets; int nr_total_params; const u64 *presets; /* nr_presets * nr_total_params */ + struct dev_ext_attribute *id_ea; + struct dev_ext_attribute *event_ea; };
/** diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index a608081bd446..8a87984195ed 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -20,6 +20,8 @@
#include "coresight-etm-perf.h" #include "coresight-priv.h" +#include "coresight-config.h" +#include "coresight-syscfg.h"
static struct pmu etm_pmu; static bool etm_perf_up; @@ -34,6 +36,11 @@ PMU_FORMAT_ATTR(timestamp, "config:" __stringify(ETM_OPT_TS)); PMU_FORMAT_ATTR(retstack, "config:" __stringify(ETM_OPT_RETSTK)); /* Sink ID - same for all ETMs */ PMU_FORMAT_ATTR(sinkid, "config2:0-31"); +/* preset - if sink ID is used as a configuration selector */ +PMU_FORMAT_ATTR(preset, "config:0-3"); +/* config ID - set if a system configuration is selected */ +PMU_FORMAT_ATTR(configid, "config2:32-63"); +
static struct attribute *etm_config_formats_attr[] = { &format_attr_cycacc.attr, @@ -41,6 +48,8 @@ static struct attribute *etm_config_formats_attr[] = { &format_attr_timestamp.attr, &format_attr_retstack.attr, &format_attr_sinkid.attr, + &format_attr_preset.attr, + &format_attr_configid.attr, NULL, };
@@ -58,9 +67,29 @@ static const struct attribute_group etm_pmu_sinks_group = { .attrs = etm_config_sinks_attr, };
+static struct attribute *etm_config_cscfg_attr[] = { + NULL, +}; + +static const struct attribute_group etm_pmu_cscfg_group = { + .name = "configurations", + .attrs = etm_config_cscfg_attr, +}; + +static struct attribute *etm_config_events_attr[] = { + NULL, +}; + +static const struct attribute_group etm_pmu_events_group = { + .name = "events", + .attrs = etm_config_events_attr, +}; + static const struct attribute_group *etm_pmu_attr_groups[] = { &etm_pmu_format_group, &etm_pmu_sinks_group, + &etm_pmu_cscfg_group, + &etm_pmu_events_group, NULL, };
@@ -219,7 +248,7 @@ static void *etm_setup_aux(struct perf_event *event, void **pages, INIT_WORK(&event_data->work, free_event_data);
/* First get the selected sink from user space. */ - if (event->attr.config2) { + if (event->attr.config2 & GENMASK_ULL(31, 0)) { id = (u32)event->attr.config2; sink = coresight_get_sink_by_id(id); } @@ -537,21 +566,17 @@ static ssize_t etm_perf_sink_name_show(struct device *dev, return scnprintf(buf, PAGE_SIZE, "0x%lx\n", (unsigned long)(ea->var)); }
-int etm_perf_add_symlink_sink(struct coresight_device *csdev) +int etm_perf_add_symlink_group(struct device *dev, + struct dev_ext_attribute **ext_attr, + const char *name, + const char *group_name) { - int ret; + struct dev_ext_attribute *ea; unsigned long hash; - const char *name; + int ret; struct device *pmu_dev = etm_pmu.dev; - struct device *dev = &csdev->dev; - struct dev_ext_attribute *ea;
- if (csdev->type != CORESIGHT_DEV_TYPE_SINK && - csdev->type != CORESIGHT_DEV_TYPE_LINKSINK) - return -EINVAL; - - if (csdev->ea != NULL) - return -EINVAL; + *ext_attr = NULL;
if (!etm_perf_up) return -EPROBE_DEFER; @@ -560,7 +585,6 @@ int etm_perf_add_symlink_sink(struct coresight_device *csdev) if (!ea) return -ENOMEM;
- name = dev_name(dev); /* See function coresight_get_sink_by_id() to know where this is used */ hash = hashlen_hash(hashlen_string(NULL, name));
@@ -574,31 +598,127 @@ int etm_perf_add_symlink_sink(struct coresight_device *csdev) ea->var = (unsigned long *)hash;
ret = sysfs_add_file_to_group(&pmu_dev->kobj, - &ea->attr.attr, "sinks"); - + &ea->attr.attr, group_name); if (!ret) - csdev->ea = ea; - + *ext_attr = ea; return ret; }
-void etm_perf_del_symlink_sink(struct coresight_device *csdev) +int etm_perf_add_symlink_sink(struct coresight_device *csdev) +{ + const char *name; + struct device *dev = &csdev->dev; + + if (csdev->type != CORESIGHT_DEV_TYPE_SINK && + csdev->type != CORESIGHT_DEV_TYPE_LINKSINK) + return -EINVAL; + + if (csdev->ea != NULL) + return -EINVAL; + + name = dev_name(dev); + return etm_perf_add_symlink_group(dev, &csdev->ea, name, "sinks"); +} + +void etm_perf_del_symlink_group(struct dev_ext_attribute *ea, const char *group_name) { struct device *pmu_dev = etm_pmu.dev; - struct dev_ext_attribute *ea = csdev->ea;
+ sysfs_remove_file_from_group(&pmu_dev->kobj, + &ea->attr.attr, group_name); +} + +void etm_perf_del_symlink_sink(struct coresight_device *csdev) +{ if (csdev->type != CORESIGHT_DEV_TYPE_SINK && csdev->type != CORESIGHT_DEV_TYPE_LINKSINK) return;
- if (!ea) + if (!csdev->ea) return;
- sysfs_remove_file_from_group(&pmu_dev->kobj, - &ea->attr.attr, "sinks"); + etm_perf_del_symlink_group(csdev->ea, "sinks"); csdev->ea = NULL; }
+/* string to contain the attribute value */ +#define CSCFG_EVENT_STR_SIZE 32 + +static ssize_t etm_perf_cscfg_event_show(struct device *dev, + struct device_attribute *dattr, + char *buf) +{ + struct dev_ext_attribute *ea; + + ea = container_of(dattr, struct dev_ext_attribute, attr); + return scnprintf(buf, PAGE_SIZE, "%s\n", (const char *)(ea->var)); +} + +static int etm_perf_add_cscfg_event(struct device *dev, struct cscfg_config_desc *cs_cfg) +{ + struct dev_ext_attribute *ea; + unsigned long hash; + int ret; + struct device *pmu_dev = etm_pmu.dev; + + ea = devm_kzalloc(dev, sizeof(*ea), GFP_KERNEL); + if (!ea) + return -ENOMEM; + + hash = (unsigned long)cs_cfg->id_ea->var; + + sysfs_attr_init(&ea->attr.attr); + ea->attr.attr.name = devm_kstrdup(dev, cs_cfg->name, GFP_KERNEL); + if (!ea->attr.attr.name) + return -ENOMEM; + + /* + * attribute value is "configid=<hash>". + * this will be what perf evaluates when the config name is used + * on the command line. + */ + ea->var = devm_kzalloc(dev, CSCFG_EVENT_STR_SIZE, GFP_KERNEL); + if (!ea->var) + return -ENOMEM; + + scnprintf(ea->var, CSCFG_EVENT_STR_SIZE, "configid=0x%lx", hash); + ea->attr.attr.mode = 0444; + ea->attr.show = etm_perf_cscfg_event_show; + + ret = sysfs_add_file_to_group(&pmu_dev->kobj, + &ea->attr.attr, "events"); + if (!ret) + cs_cfg->event_ea = ea; + return ret; +} + +int etm_perf_add_symlink_cscfg(struct device *dev, struct cscfg_config_desc *cs_cfg) +{ + int err; + + if (cs_cfg->id_ea != NULL) + return 0; + + err = etm_perf_add_symlink_group(dev, &cs_cfg->id_ea, + cs_cfg->name, "configurations"); + + if (!err) + err = etm_perf_add_cscfg_event(dev, cs_cfg); + + return err; +} + +void etm_perf_del_symlink_cscfg(struct cscfg_config_desc *cs_cfg) +{ + if (!cs_cfg->id_ea) + return; + + etm_perf_del_symlink_group(cs_cfg->id_ea, "configurations"); + etm_perf_del_symlink_group(cs_cfg->event_ea, "events"); + cs_cfg->id_ea = NULL; + cs_cfg->event_ea = NULL; +} + int __init etm_perf_init(void) { int ret; diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.h b/drivers/hwtracing/coresight/coresight-etm-perf.h index 29d90dfeba31..3646a3837a0b 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.h +++ b/drivers/hwtracing/coresight/coresight-etm-perf.h @@ -11,6 +11,7 @@ #include "coresight-priv.h"
struct coresight_device; +struct cscfg_config_desc;
/* * In both ETMv3 and v4 the maximum number of address comparator implentable @@ -69,6 +70,9 @@ static inline void *etm_perf_sink_config(struct perf_output_handle *handle) return data->snk_config; return NULL; } +int etm_perf_add_symlink_cscfg(struct device *dev, + struct cscfg_config_desc *cscfg_desc); +void etm_perf_del_symlink_cscfg(struct cscfg_config_desc *cscfg_desc); #else static inline int etm_perf_symlink(struct coresight_device *csdev, bool link) { return -EINVAL; } @@ -79,6 +83,10 @@ static inline void *etm_perf_sink_config(struct perf_output_handle *handle) { return NULL; } +int etm_perf_add_symlink_cscfg(struct device *dev, + struct cscfg_config_desc *cscfg_desc) +{ return -EINVAL; } +void etm_perf_del_symlink_cscfg(struct cscfg_config_desc *cscfg_desc) {}
#endif /* CONFIG_CORESIGHT */
diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 98ee78e3412a..8d52580daf04 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -7,6 +7,7 @@ #include <linux/platform_device.h>
#include "coresight-config.h" +#include "coresight-etm-perf.h" #include "coresight-syscfg.h"
/* @@ -85,7 +86,7 @@ static int cscfg_add_csdev_cfg(struct coresight_device *csdev, struct cscfg_config_csdev *dev_cfg = NULL; struct cscfg_config_feat_ref *feat_ref; struct cscfg_feature_csdev *feat; - int checked; + int checked, err;
/* look at each required feature and see if it matches any feature on the device */ for (checked = 0; checked < cfg_desc->nr_refs; checked++) { @@ -97,16 +98,22 @@ static int cscfg_add_csdev_cfg(struct coresight_device *csdev, return -EINVAL; if (!dev_cfg) { dev_cfg = cscfg_alloc_csdev_cfg(csdev, cfg_desc->nr_refs); - if (!dev_cfg) - return -ENOMEM; dev_cfg->desc = cfg_desc; + dev_cfg->id_hash = (unsigned long)cfg_desc->id_ea->var; } dev_cfg->feats[dev_cfg->nr_feat++] = feat; } } + /* if matched features, add config to device.*/ - if (dev_cfg) + if (dev_cfg) { + /* add config name to perf event directory if this is valid source */ + if (match_info->match_flags & CS_CFG_MATCH_CLASS_SRC_ALL) + err = etm_perf_add_symlink_cscfg(&csdev->dev, cfg_desc); + if (err) + return err; list_add(&dev_cfg->node, &csdev->syscfg_list); + }
return 0; } @@ -282,8 +289,9 @@ static int cscfg_load_config(struct cscfg_config_desc *cfg_desc) return err;
list_add(&cfg_desc->item, &cscfg_data.config_list); + err = etm_perf_add_symlink_cscfg(to_device_cscfg(), cfg_desc);
- return 0; + return err; }
/* @@ -532,7 +540,12 @@ int cscfg_create_device(void)
void cscfg_clear_device(void) { + struct cscfg_config_desc *cfg_desc; + mutex_lock(&cscfg_mutex); + list_for_each_entry(cfg_desc, &cscfg_data.config_list, item) { + etm_perf_del_symlink_cscfg(cfg_desc); + } device_unregister(to_device_cscfg()); mutex_unlock(&cscfg_mutex); }
On Fri, Oct 30, 2020 at 05:56:50PM +0000, Mike Leach wrote:
Loaded coresight configurations are registered in the cs_etm\cs_config sub directory. This extends the etm-perf code to handle these registrations, and the cs_syscfg driver to perform the registration on load.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-config.h | 5 +- .../hwtracing/coresight/coresight-etm-perf.c | 164 +++++++++++++++--- .../hwtracing/coresight/coresight-etm-perf.h | 8 + .../hwtracing/coresight/coresight-syscfg.c | 23 ++- 4 files changed, 172 insertions(+), 28 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index a3d374ebb70f..372f29a59688 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -154,7 +154,8 @@ struct cscfg_config_feat_ref {
- @nr_presets: Number of sets of presets supplied by this configuration.
- @nr_total_params: Sum of all parameters declared by used features
- @presets: Array of preset values.
- @id_ea: Extended attribute for perf configid value
*/
- @event_ea: Extended attribute for perf event value
struct cscfg_config_desc { const char *name; @@ -165,6 +166,8 @@ struct cscfg_config_desc { int nr_presets; int nr_total_params; const u64 *presets; /* nr_presets * nr_total_params */
- struct dev_ext_attribute *id_ea;
- struct dev_ext_attribute *event_ea;
}; /** diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index a608081bd446..8a87984195ed 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -20,6 +20,8 @@ #include "coresight-etm-perf.h" #include "coresight-priv.h" +#include "coresight-config.h"
Alphabetical order
+#include "coresight-syscfg.h" static struct pmu etm_pmu; static bool etm_perf_up; @@ -34,6 +36,11 @@ PMU_FORMAT_ATTR(timestamp, "config:" __stringify(ETM_OPT_TS)); PMU_FORMAT_ATTR(retstack, "config:" __stringify(ETM_OPT_RETSTK)); /* Sink ID - same for all ETMs */ PMU_FORMAT_ATTR(sinkid, "config2:0-31"); +/* preset - if sink ID is used as a configuration selector */ +PMU_FORMAT_ATTR(preset, "config:0-3");
Please move this before sinkid to keep the "config" together. I also looked at bit 0-3 of the ETMCR on ETMv3.x and I don't think we'll be using those bits any time soon.
+/* config ID - set if a system configuration is selected */ +PMU_FORMAT_ATTR(configid, "config2:32-63");
static struct attribute *etm_config_formats_attr[] = { &format_attr_cycacc.attr, @@ -41,6 +48,8 @@ static struct attribute *etm_config_formats_attr[] = { &format_attr_timestamp.attr, &format_attr_retstack.attr, &format_attr_sinkid.attr,
- &format_attr_preset.attr,
- &format_attr_configid.attr, NULL,
}; @@ -58,9 +67,29 @@ static const struct attribute_group etm_pmu_sinks_group = { .attrs = etm_config_sinks_attr, }; +static struct attribute *etm_config_cscfg_attr[] = {
- NULL,
+};
+static const struct attribute_group etm_pmu_cscfg_group = {
- .name = "configurations",
- .attrs = etm_config_cscfg_attr,
+};
+static struct attribute *etm_config_events_attr[] = {
- NULL,
+};
+static const struct attribute_group etm_pmu_events_group = {
- .name = "events",
- .attrs = etm_config_events_attr,
+};
static const struct attribute_group *etm_pmu_attr_groups[] = { &etm_pmu_format_group, &etm_pmu_sinks_group,
- &etm_pmu_cscfg_group,
- &etm_pmu_events_group, NULL,
}; @@ -219,7 +248,7 @@ static void *etm_setup_aux(struct perf_event *event, void **pages, INIT_WORK(&event_data->work, free_event_data); /* First get the selected sink from user space. */
- if (event->attr.config2) {
- if (event->attr.config2 & GENMASK_ULL(31, 0)) { id = (u32)event->attr.config2; sink = coresight_get_sink_by_id(id); }
@@ -537,21 +566,17 @@ static ssize_t etm_perf_sink_name_show(struct device *dev, return scnprintf(buf, PAGE_SIZE, "0x%lx\n", (unsigned long)(ea->var)); } -int etm_perf_add_symlink_sink(struct coresight_device *csdev) +int etm_perf_add_symlink_group(struct device *dev,
struct dev_ext_attribute **ext_attr,
const char *name,
const char *group_name)
{
- int ret;
- struct dev_ext_attribute *ea; unsigned long hash;
- const char *name;
- int ret; struct device *pmu_dev = etm_pmu.dev;
- struct device *dev = &csdev->dev;
- struct dev_ext_attribute *ea;
- if (csdev->type != CORESIGHT_DEV_TYPE_SINK &&
csdev->type != CORESIGHT_DEV_TYPE_LINKSINK)
return -EINVAL;
- if (csdev->ea != NULL)
return -EINVAL;
- *ext_attr = NULL;
if (!etm_perf_up) return -EPROBE_DEFER; @@ -560,7 +585,6 @@ int etm_perf_add_symlink_sink(struct coresight_device *csdev) if (!ea) return -ENOMEM;
- name = dev_name(dev); /* See function coresight_get_sink_by_id() to know where this is used */ hash = hashlen_hash(hashlen_string(NULL, name));
@@ -574,31 +598,127 @@ int etm_perf_add_symlink_sink(struct coresight_device *csdev) ea->var = (unsigned long *)hash; ret = sysfs_add_file_to_group(&pmu_dev->kobj,
&ea->attr.attr, "sinks");
if (!ret)&ea->attr.attr, group_name);
csdev->ea = ea;
return ret;*ext_attr = ea;
} -void etm_perf_del_symlink_sink(struct coresight_device *csdev) +int etm_perf_add_symlink_sink(struct coresight_device *csdev) +{
- const char *name;
- struct device *dev = &csdev->dev;
- if (csdev->type != CORESIGHT_DEV_TYPE_SINK &&
csdev->type != CORESIGHT_DEV_TYPE_LINKSINK)
return -EINVAL;
- if (csdev->ea != NULL)
return -EINVAL;
- name = dev_name(dev);
- return etm_perf_add_symlink_group(dev, &csdev->ea, name, "sinks");
+}
+void etm_perf_del_symlink_group(struct dev_ext_attribute *ea, const char *group_name) { struct device *pmu_dev = etm_pmu.dev;
- struct dev_ext_attribute *ea = csdev->ea;
- sysfs_remove_file_from_group(&pmu_dev->kobj,
&ea->attr.attr, group_name);
+}
+void etm_perf_del_symlink_sink(struct coresight_device *csdev) +{ if (csdev->type != CORESIGHT_DEV_TYPE_SINK && csdev->type != CORESIGHT_DEV_TYPE_LINKSINK) return;
- if (!ea)
- if (!csdev->ea) return;
- sysfs_remove_file_from_group(&pmu_dev->kobj,
&ea->attr.attr, "sinks");
- etm_perf_del_symlink_group(csdev->ea, "sinks"); csdev->ea = NULL;
} +/* string to contain the attribute value */ +#define CSCFG_EVENT_STR_SIZE 32
+static ssize_t etm_perf_cscfg_event_show(struct device *dev,
struct device_attribute *dattr,
char *buf)
+{
- struct dev_ext_attribute *ea;
- ea = container_of(dattr, struct dev_ext_attribute, attr);
- return scnprintf(buf, PAGE_SIZE, "%s\n", (const char *)(ea->var));
+}
+static int etm_perf_add_cscfg_event(struct device *dev, struct cscfg_config_desc *cs_cfg) +{
- struct dev_ext_attribute *ea;
- unsigned long hash;
- int ret;
- struct device *pmu_dev = etm_pmu.dev;
- ea = devm_kzalloc(dev, sizeof(*ea), GFP_KERNEL);
- if (!ea)
return -ENOMEM;
- hash = (unsigned long)cs_cfg->id_ea->var;
- sysfs_attr_init(&ea->attr.attr);
- ea->attr.attr.name = devm_kstrdup(dev, cs_cfg->name, GFP_KERNEL);
- if (!ea->attr.attr.name)
return -ENOMEM;
- /*
* attribute value is "configid=<hash>".
* this will be what perf evaluates when the config name is used
* on the command line.
*/
- ea->var = devm_kzalloc(dev, CSCFG_EVENT_STR_SIZE, GFP_KERNEL);
- if (!ea->var)
return -ENOMEM;
- scnprintf(ea->var, CSCFG_EVENT_STR_SIZE, "configid=0x%lx", hash);
- ea->attr.attr.mode = 0444;
- ea->attr.show = etm_perf_cscfg_event_show;
- ret = sysfs_add_file_to_group(&pmu_dev->kobj,
&ea->attr.attr, "events");
- if (!ret)
cs_cfg->event_ea = ea;
- return ret;
+}
+int etm_perf_add_symlink_cscfg(struct device *dev, struct cscfg_config_desc *cs_cfg) +{
- int err;
- if (cs_cfg->id_ea != NULL)
return 0;
- err = etm_perf_add_symlink_group(dev, &cs_cfg->id_ea,
cs_cfg->name, "configurations");
- if (!err)
err = etm_perf_add_cscfg_event(dev, cs_cfg);
- return err;
+}
+void etm_perf_del_symlink_cscfg(struct cscfg_config_desc *cs_cfg) +{
- if (!cs_cfg->id_ea)
return;
- etm_perf_del_symlink_group(cs_cfg->id_ea, "configurations");
- etm_perf_del_symlink_group(cs_cfg->event_ea, "events");
- cs_cfg->id_ea = NULL;
- cs_cfg->event_ea = NULL;
+}
int __init etm_perf_init(void) { int ret; diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.h b/drivers/hwtracing/coresight/coresight-etm-perf.h index 29d90dfeba31..3646a3837a0b 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.h +++ b/drivers/hwtracing/coresight/coresight-etm-perf.h @@ -11,6 +11,7 @@ #include "coresight-priv.h" struct coresight_device; +struct cscfg_config_desc; /*
- In both ETMv3 and v4 the maximum number of address comparator implentable
@@ -69,6 +70,9 @@ static inline void *etm_perf_sink_config(struct perf_output_handle *handle) return data->snk_config; return NULL; } +int etm_perf_add_symlink_cscfg(struct device *dev,
struct cscfg_config_desc *cscfg_desc);
+void etm_perf_del_symlink_cscfg(struct cscfg_config_desc *cscfg_desc); #else static inline int etm_perf_symlink(struct coresight_device *csdev, bool link) { return -EINVAL; } @@ -79,6 +83,10 @@ static inline void *etm_perf_sink_config(struct perf_output_handle *handle) { return NULL; } +int etm_perf_add_symlink_cscfg(struct device *dev,
struct cscfg_config_desc *cscfg_desc)
+{ return -EINVAL; } +void etm_perf_del_symlink_cscfg(struct cscfg_config_desc *cscfg_desc) {} #endif /* CONFIG_CORESIGHT */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 98ee78e3412a..8d52580daf04 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -7,6 +7,7 @@ #include <linux/platform_device.h> #include "coresight-config.h" +#include "coresight-etm-perf.h" #include "coresight-syscfg.h" /* @@ -85,7 +86,7 @@ static int cscfg_add_csdev_cfg(struct coresight_device *csdev, struct cscfg_config_csdev *dev_cfg = NULL; struct cscfg_config_feat_ref *feat_ref; struct cscfg_feature_csdev *feat;
- int checked;
- int checked, err;
/* look at each required feature and see if it matches any feature on the device */ for (checked = 0; checked < cfg_desc->nr_refs; checked++) { @@ -97,16 +98,22 @@ static int cscfg_add_csdev_cfg(struct coresight_device *csdev, return -EINVAL; if (!dev_cfg) { dev_cfg = cscfg_alloc_csdev_cfg(csdev, cfg_desc->nr_refs);
if (!dev_cfg)
return -ENOMEM;
As far as I can tell cscfg_alloc_csdev() can still return NULL and as such the check shouldn't be removed.
dev_cfg->desc = cfg_desc;
dev_cfg->id_hash = (unsigned long)cfg_desc->id_ea->var;
Please add a comment to say that cfg_desc->id_ea->var is initalised in etm_perf_add_symlink_cscfg().
} dev_cfg->feats[dev_cfg->nr_feat++] = feat; }
}
- /* if matched features, add config to device.*/
- if (dev_cfg)
- if (dev_cfg) {
/* add config name to perf event directory if this is valid source */
if (match_info->match_flags & CS_CFG_MATCH_CLASS_SRC_ALL)
To me all configurations should be added and as such there shouldn't be a need for a check here. I'm also puzzled about the comment, especially the "valid source" part. To me a source is an ETM or some device that produce traces but complex configuration also applies to CTIs.
err = etm_perf_add_symlink_cscfg(&csdev->dev, cfg_desc);
Why is this added here when the same configuration is also added in cscfg_load_config()?
if (err)
list_add(&dev_cfg->node, &csdev->syscfg_list);return err;
- }
return 0; } @@ -282,8 +289,9 @@ static int cscfg_load_config(struct cscfg_config_desc *cfg_desc) return err; list_add(&cfg_desc->item, &cscfg_data.config_list);
- err = etm_perf_add_symlink_cscfg(to_device_cscfg(), cfg_desc);
I think this is the right place to do this.
I'm done with this patch - I'll continue on Monday.
Thanks, Mathieu
- return 0;
- return err;
} /* @@ -532,7 +540,12 @@ int cscfg_create_device(void) void cscfg_clear_device(void) {
- struct cscfg_config_desc *cfg_desc;
- mutex_lock(&cscfg_mutex);
- list_for_each_entry(cfg_desc, &cscfg_data.config_list, item) {
etm_perf_del_symlink_cscfg(cfg_desc);
- } device_unregister(to_device_cscfg()); mutex_unlock(&cscfg_mutex);
}
2.17.1
Hi Mathieu,
On Fri, 20 Nov 2020 at 18:52, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Fri, Oct 30, 2020 at 05:56:50PM +0000, Mike Leach wrote:
Loaded coresight configurations are registered in the cs_etm\cs_config sub directory. This extends the etm-perf code to handle these registrations, and the cs_syscfg driver to perform the registration on load.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-config.h | 5 +- .../hwtracing/coresight/coresight-etm-perf.c | 164 +++++++++++++++--- .../hwtracing/coresight/coresight-etm-perf.h | 8 + .../hwtracing/coresight/coresight-syscfg.c | 23 ++- 4 files changed, 172 insertions(+), 28 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index a3d374ebb70f..372f29a59688 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -154,7 +154,8 @@ struct cscfg_config_feat_ref {
- @nr_presets: Number of sets of presets supplied by this configuration.
- @nr_total_params: Sum of all parameters declared by used features
- @presets: Array of preset values.
- @id_ea: Extended attribute for perf configid value
*/
- @event_ea: Extended attribute for perf event value
struct cscfg_config_desc { const char *name; @@ -165,6 +166,8 @@ struct cscfg_config_desc { int nr_presets; int nr_total_params; const u64 *presets; /* nr_presets * nr_total_params */
struct dev_ext_attribute *id_ea;
struct dev_ext_attribute *event_ea;
};
/** diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index a608081bd446..8a87984195ed 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -20,6 +20,8 @@
#include "coresight-etm-perf.h" #include "coresight-priv.h" +#include "coresight-config.h"
Alphabetical order
OK
+#include "coresight-syscfg.h"
static struct pmu etm_pmu; static bool etm_perf_up; @@ -34,6 +36,11 @@ PMU_FORMAT_ATTR(timestamp, "config:" __stringify(ETM_OPT_TS)); PMU_FORMAT_ATTR(retstack, "config:" __stringify(ETM_OPT_RETSTK)); /* Sink ID - same for all ETMs */ PMU_FORMAT_ATTR(sinkid, "config2:0-31"); +/* preset - if sink ID is used as a configuration selector */ +PMU_FORMAT_ATTR(preset, "config:0-3");
Please move this before sinkid to keep the "config" together. I also looked at bit 0-3 of the ETMCR on ETMv3.x and I don't think we'll be using those bits any time soon.
Agreed.
+/* config ID - set if a system configuration is selected */ +PMU_FORMAT_ATTR(configid, "config2:32-63");
static struct attribute *etm_config_formats_attr[] = { &format_attr_cycacc.attr, @@ -41,6 +48,8 @@ static struct attribute *etm_config_formats_attr[] = { &format_attr_timestamp.attr, &format_attr_retstack.attr, &format_attr_sinkid.attr,
&format_attr_preset.attr,
&format_attr_configid.attr, NULL,
};
@@ -58,9 +67,29 @@ static const struct attribute_group etm_pmu_sinks_group = { .attrs = etm_config_sinks_attr, };
+static struct attribute *etm_config_cscfg_attr[] = {
NULL,
+};
+static const struct attribute_group etm_pmu_cscfg_group = {
.name = "configurations",
.attrs = etm_config_cscfg_attr,
+};
+static struct attribute *etm_config_events_attr[] = {
NULL,
+};
+static const struct attribute_group etm_pmu_events_group = {
.name = "events",
.attrs = etm_config_events_attr,
+};
static const struct attribute_group *etm_pmu_attr_groups[] = { &etm_pmu_format_group, &etm_pmu_sinks_group,
&etm_pmu_cscfg_group,
&etm_pmu_events_group, NULL,
};
@@ -219,7 +248,7 @@ static void *etm_setup_aux(struct perf_event *event, void **pages, INIT_WORK(&event_data->work, free_event_data);
/* First get the selected sink from user space. */
if (event->attr.config2) {
if (event->attr.config2 & GENMASK_ULL(31, 0)) { id = (u32)event->attr.config2; sink = coresight_get_sink_by_id(id); }
@@ -537,21 +566,17 @@ static ssize_t etm_perf_sink_name_show(struct device *dev, return scnprintf(buf, PAGE_SIZE, "0x%lx\n", (unsigned long)(ea->var)); }
-int etm_perf_add_symlink_sink(struct coresight_device *csdev) +int etm_perf_add_symlink_group(struct device *dev,
struct dev_ext_attribute **ext_attr,
const char *name,
const char *group_name)
{
int ret;
struct dev_ext_attribute *ea; unsigned long hash;
const char *name;
int ret; struct device *pmu_dev = etm_pmu.dev;
struct device *dev = &csdev->dev;
struct dev_ext_attribute *ea;
if (csdev->type != CORESIGHT_DEV_TYPE_SINK &&
csdev->type != CORESIGHT_DEV_TYPE_LINKSINK)
return -EINVAL;
if (csdev->ea != NULL)
return -EINVAL;
*ext_attr = NULL; if (!etm_perf_up) return -EPROBE_DEFER;
@@ -560,7 +585,6 @@ int etm_perf_add_symlink_sink(struct coresight_device *csdev) if (!ea) return -ENOMEM;
name = dev_name(dev); /* See function coresight_get_sink_by_id() to know where this is used */ hash = hashlen_hash(hashlen_string(NULL, name));
@@ -574,31 +598,127 @@ int etm_perf_add_symlink_sink(struct coresight_device *csdev) ea->var = (unsigned long *)hash;
ret = sysfs_add_file_to_group(&pmu_dev->kobj,
&ea->attr.attr, "sinks");
&ea->attr.attr, group_name); if (!ret)
csdev->ea = ea;
*ext_attr = ea; return ret;
}
-void etm_perf_del_symlink_sink(struct coresight_device *csdev) +int etm_perf_add_symlink_sink(struct coresight_device *csdev) +{
const char *name;
struct device *dev = &csdev->dev;
if (csdev->type != CORESIGHT_DEV_TYPE_SINK &&
csdev->type != CORESIGHT_DEV_TYPE_LINKSINK)
return -EINVAL;
if (csdev->ea != NULL)
return -EINVAL;
name = dev_name(dev);
return etm_perf_add_symlink_group(dev, &csdev->ea, name, "sinks");
+}
+void etm_perf_del_symlink_group(struct dev_ext_attribute *ea, const char *group_name) { struct device *pmu_dev = etm_pmu.dev;
struct dev_ext_attribute *ea = csdev->ea;
sysfs_remove_file_from_group(&pmu_dev->kobj,
&ea->attr.attr, group_name);
+}
+void etm_perf_del_symlink_sink(struct coresight_device *csdev) +{ if (csdev->type != CORESIGHT_DEV_TYPE_SINK && csdev->type != CORESIGHT_DEV_TYPE_LINKSINK) return;
if (!ea)
if (!csdev->ea) return;
sysfs_remove_file_from_group(&pmu_dev->kobj,
&ea->attr.attr, "sinks");
etm_perf_del_symlink_group(csdev->ea, "sinks"); csdev->ea = NULL;
}
+/* string to contain the attribute value */ +#define CSCFG_EVENT_STR_SIZE 32
+static ssize_t etm_perf_cscfg_event_show(struct device *dev,
struct device_attribute *dattr,
char *buf)
+{
struct dev_ext_attribute *ea;
ea = container_of(dattr, struct dev_ext_attribute, attr);
return scnprintf(buf, PAGE_SIZE, "%s\n", (const char *)(ea->var));
+}
+static int etm_perf_add_cscfg_event(struct device *dev, struct cscfg_config_desc *cs_cfg) +{
struct dev_ext_attribute *ea;
unsigned long hash;
int ret;
struct device *pmu_dev = etm_pmu.dev;
ea = devm_kzalloc(dev, sizeof(*ea), GFP_KERNEL);
if (!ea)
return -ENOMEM;
hash = (unsigned long)cs_cfg->id_ea->var;
sysfs_attr_init(&ea->attr.attr);
ea->attr.attr.name = devm_kstrdup(dev, cs_cfg->name, GFP_KERNEL);
if (!ea->attr.attr.name)
return -ENOMEM;
/*
* attribute value is "configid=<hash>".
* this will be what perf evaluates when the config name is used
* on the command line.
*/
ea->var = devm_kzalloc(dev, CSCFG_EVENT_STR_SIZE, GFP_KERNEL);
if (!ea->var)
return -ENOMEM;
scnprintf(ea->var, CSCFG_EVENT_STR_SIZE, "configid=0x%lx", hash);
ea->attr.attr.mode = 0444;
ea->attr.show = etm_perf_cscfg_event_show;
ret = sysfs_add_file_to_group(&pmu_dev->kobj,
&ea->attr.attr, "events");
if (!ret)
cs_cfg->event_ea = ea;
return ret;
+}
+int etm_perf_add_symlink_cscfg(struct device *dev, struct cscfg_config_desc *cs_cfg) +{
int err;
if (cs_cfg->id_ea != NULL)
return 0;
err = etm_perf_add_symlink_group(dev, &cs_cfg->id_ea,
cs_cfg->name, "configurations");
if (!err)
err = etm_perf_add_cscfg_event(dev, cs_cfg);
return err;
+}
+void etm_perf_del_symlink_cscfg(struct cscfg_config_desc *cs_cfg) +{
if (!cs_cfg->id_ea)
return;
etm_perf_del_symlink_group(cs_cfg->id_ea, "configurations");
etm_perf_del_symlink_group(cs_cfg->event_ea, "events");
cs_cfg->id_ea = NULL;
cs_cfg->event_ea = NULL;
+}
int __init etm_perf_init(void) { int ret; diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.h b/drivers/hwtracing/coresight/coresight-etm-perf.h index 29d90dfeba31..3646a3837a0b 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.h +++ b/drivers/hwtracing/coresight/coresight-etm-perf.h @@ -11,6 +11,7 @@ #include "coresight-priv.h"
struct coresight_device; +struct cscfg_config_desc;
/*
- In both ETMv3 and v4 the maximum number of address comparator implentable
@@ -69,6 +70,9 @@ static inline void *etm_perf_sink_config(struct perf_output_handle *handle) return data->snk_config; return NULL; } +int etm_perf_add_symlink_cscfg(struct device *dev,
struct cscfg_config_desc *cscfg_desc);
+void etm_perf_del_symlink_cscfg(struct cscfg_config_desc *cscfg_desc); #else static inline int etm_perf_symlink(struct coresight_device *csdev, bool link) { return -EINVAL; } @@ -79,6 +83,10 @@ static inline void *etm_perf_sink_config(struct perf_output_handle *handle) { return NULL; } +int etm_perf_add_symlink_cscfg(struct device *dev,
struct cscfg_config_desc *cscfg_desc)
+{ return -EINVAL; } +void etm_perf_del_symlink_cscfg(struct cscfg_config_desc *cscfg_desc) {}
#endif /* CONFIG_CORESIGHT */
diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 98ee78e3412a..8d52580daf04 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -7,6 +7,7 @@ #include <linux/platform_device.h>
#include "coresight-config.h" +#include "coresight-etm-perf.h" #include "coresight-syscfg.h"
/* @@ -85,7 +86,7 @@ static int cscfg_add_csdev_cfg(struct coresight_device *csdev, struct cscfg_config_csdev *dev_cfg = NULL; struct cscfg_config_feat_ref *feat_ref; struct cscfg_feature_csdev *feat;
int checked;
int checked, err; /* look at each required feature and see if it matches any feature on the device */ for (checked = 0; checked < cfg_desc->nr_refs; checked++) {
@@ -97,16 +98,22 @@ static int cscfg_add_csdev_cfg(struct coresight_device *csdev, return -EINVAL; if (!dev_cfg) { dev_cfg = cscfg_alloc_csdev_cfg(csdev, cfg_desc->nr_refs);
if (!dev_cfg)
return -ENOMEM;
As far as I can tell cscfg_alloc_csdev() can still return NULL and as such the check shouldn't be removed.
dev_cfg->desc = cfg_desc;
dev_cfg->id_hash = (unsigned long)cfg_desc->id_ea->var;
Please add a comment to say that cfg_desc->id_ea->var is initalised in etm_perf_add_symlink_cscfg().
} dev_cfg->feats[dev_cfg->nr_feat++] = feat; } }
/* if matched features, add config to device.*/
if (dev_cfg)
if (dev_cfg) {
/* add config name to perf event directory if this is valid source */
if (match_info->match_flags & CS_CFG_MATCH_CLASS_SRC_ALL)
To me all configurations should be added and as such there shouldn't be a need for a check here. I'm also puzzled about the comment, especially the "valid source" part. To me a source is an ETM or some device that produce traces but complex configuration also applies to CTIs.
Agreed - I think this was an error due to stopping work on this then restarting. Re-worked to be consistent,
err = etm_perf_add_symlink_cscfg(&csdev->dev, cfg_desc);
Why is this added here when the same configuration is also added in cscfg_load_config()?
As above - interupt error.
Thanks
Mike
if (err)
return err; list_add(&dev_cfg->node, &csdev->syscfg_list);
} return 0;
} @@ -282,8 +289,9 @@ static int cscfg_load_config(struct cscfg_config_desc *cfg_desc) return err;
list_add(&cfg_desc->item, &cscfg_data.config_list);
err = etm_perf_add_symlink_cscfg(to_device_cscfg(), cfg_desc);
I think this is the right place to do this.
I'm done with this patch - I'll continue on Monday.
Thanks, Mathieu
return 0;
return err;
}
/* @@ -532,7 +540,12 @@ int cscfg_create_device(void)
void cscfg_clear_device(void) {
struct cscfg_config_desc *cfg_desc;
mutex_lock(&cscfg_mutex);
list_for_each_entry(cfg_desc, &cscfg_data.config_list, item) {
etm_perf_del_symlink_cscfg(cfg_desc);
} device_unregister(to_device_cscfg()); mutex_unlock(&cscfg_mutex);
}
2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
Adds in handlers to allow the ETMv4 to use the complex configuration support. Features and configurations can be loaded and selected in the device.
Signed-off-by: Mike Leach mike.leach@linaro.org --- drivers/hwtracing/coresight/Makefile | 3 +- .../hwtracing/coresight/coresight-etm4x-cfg.c | 181 ++++++++++++++++++ .../hwtracing/coresight/coresight-etm4x-cfg.h | 29 +++ .../coresight/coresight-etm4x-core.c | 36 +++- .../coresight/coresight-etm4x-sysfs.c | 3 + 5 files changed, 249 insertions(+), 3 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-etm4x-cfg.c create mode 100644 drivers/hwtracing/coresight/coresight-etm4x-cfg.h
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index daad9f103a78..ea544206204d 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -16,7 +16,8 @@ obj-$(CONFIG_CORESIGHT_SOURCE_ETM3X) += coresight-etm3x.o coresight-etm3x-y := coresight-etm3x-core.o coresight-etm-cp14.o \ coresight-etm3x-sysfs.o obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o -coresight-etm4x-y := coresight-etm4x-core.o coresight-etm4x-sysfs.o +coresight-etm4x-y := coresight-etm4x-core.o coresight-etm4x-sysfs.o \ + coresight-etm4x-cfg.o obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o obj-$(CONFIG_CORESIGHT_CPU_DEBUG) += coresight-cpu-debug.o obj-$(CONFIG_CORESIGHT_CATU) += coresight-catu.o diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c new file mode 100644 index 000000000000..9589d43e7947 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2020 Linaro Limited. All rights reserved. + * Author: Mike Leach mike.leach@linaro.org + */ + +#include "coresight-etm4x.h" +#include "coresight-etm4x-cfg.h" +#include "coresight-priv.h" +#include "coresight-syscfg.h" + +/** + * etm4_cfg_map_reg_offset - validate and map the register offset into a + * location in the driver config struct. + * + * Limits the number of registers that can be accessed and programmed in + * features, to those which are used to control the trace capture parameters. + * + * Omits or limits access to those which the driver must use exclusively. + * + * Invalid offsets will result in fail code return and feature load failure. + * + * @drvdata: driver data to map into. + * @reg: register to map. + * @offset: device offset for the register + */ +static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata, + struct cscfg_reg_csdev *reg, u32 offset) +{ + int err = -EINVAL, idx; + struct etmv4_config *drvcfg = &drvdata->config; + u32 off_mask; + +#define CHECKREG(cval, elem) \ + { \ + if (offset == cval) { \ + reg->drv_store = &drvcfg->elem; \ + err = 0; \ + break; \ + } \ + } + +#define CHECKREGIDX(cval, elem, off_idx) \ + { \ + if (off_mask == cval) { \ + reg->drv_store = &drvcfg->elem[off_idx]; \ + err = 0; \ + break; \ + } \ + } + + if (((offset >= TRCEVENTCTL0R) && (offset <= TRCVIPCSSCTLR)) || + ((offset >= TRCSEQRSTEVR) && (offset <= TRCEXTINSELR)) || + ((offset >= TRCCIDCCTLR0) && (offset <= TRCVMIDCCTLR1))) { + do { + CHECKREG(TRCEVENTCTL0R, eventctrl0); + CHECKREG(TRCEVENTCTL1R, eventctrl1); + CHECKREG(TRCSTALLCTLR, stall_ctrl); + CHECKREG(TRCTSCTLR, ts_ctrl); + CHECKREG(TRCSYNCPR, syncfreq); + CHECKREG(TRCCCCTLR, ccctlr); + CHECKREG(TRCBBCTLR, bb_ctrl); + CHECKREG(TRCVICTLR, vinst_ctrl); + CHECKREG(TRCVIIECTLR, viiectlr); + CHECKREG(TRCVISSCTLR, vissctlr); + CHECKREG(TRCVIPCSSCTLR, vipcssctlr); + CHECKREG(TRCSEQRSTEVR, seq_rst); + CHECKREG(TRCSEQSTR, seq_state); + CHECKREG(TRCEXTINSELR, ext_inp); + CHECKREG(TRCCIDCCTLR0, ctxid_mask0); + CHECKREG(TRCCIDCCTLR1, ctxid_mask1); + CHECKREG(TRCVMIDCCTLR0, vmid_mask0); + CHECKREG(TRCVMIDCCTLR1, vmid_mask1); + } while (0); + } else if ((offset & GENMASK(11, 4)) == TRCSEQEVRn(0)) { + /* sequencer state control registers */ + idx = (offset & GENMASK(3, 0)) / 4; + if (idx < ETM_MAX_SEQ_STATES) { + reg->drv_store = &drvcfg->seq_ctrl[idx]; + err = 0; + } + } else if ((offset >= TRCSSCCRn(0)) && (offset <= TRCSSPCICRn(7))) { + /* 32 bit, 8 off indexed register sets */ + idx = (offset & GENMASK(4, 0)) / 4; + off_mask = (offset & GENMASK(11, 5)); + do { + CHECKREGIDX(TRCSSCCRn(0), ss_ctrl, idx); + CHECKREGIDX(TRCSSCSRn(0), ss_status, idx); + CHECKREGIDX(TRCSSPCICRn(0), ss_pe_cmp, idx); + } while (0); + } else if ((offset >= TRCCIDCVRn(0)) && (offset <= TRCVMIDCVRn(7))) { + /* 64 bit, 8 off indexed register sets */ + idx = (offset & GENMASK(5, 0)) / 8; + off_mask = (offset & GENMASK(11, 6)); + do { + CHECKREGIDX(TRCCIDCVRn(0), ctxid_pid, idx); + CHECKREGIDX(TRCVMIDCVRn(0), vmid_val, idx); + } while (0); + } else if ((offset >= TRCRSCTLRn(2)) && + (offset <= TRCRSCTLRn((ETM_MAX_RES_SEL - 1)))) { + /* 32 bit resource selection regs, 32 off, skip fixed 0,1 */ + idx = (offset & GENMASK(6, 0)) / 4; + if (idx < ETM_MAX_RES_SEL) { + reg->drv_store = &drvcfg->res_ctrl[idx]; + err = 0; + } + } else if ((offset >= TRCACVRn(0)) && + (offset <= TRCACATRn((ETM_MAX_SINGLE_ADDR_CMP - 1)))) { + /* 64 bit addr cmp regs, 16 off */ + idx = (offset & GENMASK(6, 0)) / 8; + off_mask = offset & GENMASK(11, 7); + do { + CHECKREGIDX(TRCACVRn(0), addr_val, idx); + CHECKREGIDX(TRCACATRn(0), addr_acc, idx); + } while (0); + } else if ((offset >= TRCCNTRLDVRn(0)) && + (offset <= TRCCNTVRn((ETMv4_MAX_CNTR - 1)))) { + /* 32 bit counter regs, 4 off (ETMv4_MAX_CNTR - 1) */ + idx = (offset & GENMASK(3, 0)) / 4; + off_mask = offset & GENMASK(11, 4); + do { + CHECKREGIDX(TRCCNTRLDVRn(0), cntrldvr, idx); + CHECKREGIDX(TRCCNTCTLRn(0), cntr_ctrl, idx); + CHECKREGIDX(TRCCNTVRn(0), cntr_val, idx); + } while (0); + } + return err; +} + +/** + * etm4_cfg_load_feature - load a feature into a device instance. + * + * @csdev: An ETMv4 CoreSight device. + * @feat: The feature to be loaded. + * + * The function will load a feature instance into the device, checking that + * the register definitions are valid for the device. + * + * Parameter and register definitions will be converted into internal + * structures that are used to set the values in the driver when the + * feature is enabled for the device. + * + * The feature spinlock pointer is initialised to the same spinlock + * that the driver uses to protect the internal register values. + */ +static int etm4_cfg_load_feature(struct coresight_device *csdev, + struct cscfg_feature_csdev *feat) +{ + struct device *dev = csdev->dev.parent; + struct etmv4_drvdata *drvdata = dev_get_drvdata(dev); + const struct cscfg_feature_desc *feat_desc = feat->desc; + u32 offset; + int i = 0, err = 0; + + /* essential we set the device spinlock */ + feat->csdev_spinlock = &drvdata->spinlock; + + /* process the register descriptions */ + for (i = 0; i < feat->nr_regs && !err; i++) { + offset = feat_desc->regs[i].flags & CS_CFG_REG_ID_MASK; + err = etm4_cfg_map_reg_offset(drvdata, &feat->regs[i], offset); + } + return err; +} + +/* match information when loading configurations */ +#define CS_CFG_ETM4_MATCH_FLAGS (CS_CFG_MATCH_CLASS_SRC_ALL | \ + CS_CFG_MATCH_CLASS_SRC_ETM4) + +int etm4_cs_cfg_register(struct coresight_device *csdev, const char *dev_name) +{ + struct cscfg_match_info cfg_info; + struct cscfg_csdev_feat_ops ops; + + cfg_info.dev_name = dev_name; + cfg_info.match_flags = CS_CFG_ETM4_MATCH_FLAGS; + + ops.load_feat = &etm4_cfg_load_feature; + + return cscfg_register_csdev(csdev, &cfg_info, &ops); +} diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.h b/drivers/hwtracing/coresight/coresight-etm4x-cfg.h new file mode 100644 index 000000000000..bf33c720b5e9 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. + */ + +#ifndef _CORESIGHT_CORESIGHT_ETM4X_CFG_H +#define _CORESIGHT_CORESIGHT_ETM4X_CFG_H + +#include "coresight-config.h" +#include "coresight-etm4x.h" + +/* ETMv4 specific config defines */ + +/* resource IDs */ + +#define ETM4_CFG_RES_CTR 0x00001000 +#define ETM4_CFG_RES_CMP 0x00002000 +#define ETM4_CFG_RES_CMP_PAIR0 0x00003000 +#define ETM4_CFG_RES_CMP_PAIR1 0x00004000 +#define ETM4_CFG_RES_SEL 0x00005000 +#define ETM4_CFG_RES_SEL_PAIR0 0x00006000 +#define ETM4_CFG_RES_SEL_PAIR1 0x00007000 +#define ETM4_CFG_RES_SEQ 0x00008000 +#define ETM4_CFG_RES_TS 0x00009000 +#define ETM4_CFG_RES_MASK 0x0000F000 + +int etm4_cs_cfg_register(struct coresight_device *csdev, const char *dev_name); + +#endif /* _CORESIGHT_CORESIGHT_ETM4X_CFG_H */ diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 6096d7abf80d..88213aa7a72e 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -34,6 +34,8 @@
#include "coresight-etm4x.h" #include "coresight-etm-perf.h" +#include "coresight-etm4x-cfg.h" +#include "coresight-syscfg.h"
static int boot_enable; module_param(boot_enable, int, 0444); @@ -321,12 +323,15 @@ static int etm4_config_timestamp_event(struct etmv4_drvdata *drvdata) return ret; }
-static int etm4_parse_event_config(struct etmv4_drvdata *drvdata, +static int etm4_parse_event_config(struct coresight_device *csdev, struct perf_event *event) { int ret = 0; + struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); struct etmv4_config *config = &drvdata->config; struct perf_event_attr *attr = &event->attr; + unsigned long cfg_id; + int preset;
if (!attr) { ret = -EINVAL; @@ -384,6 +389,19 @@ static int etm4_parse_event_config(struct etmv4_drvdata *drvdata, /* bit[12], Return stack enable bit */ config->cfg |= BIT(12);
+ /* + * Set any selected configuration and preset. + * + * This extracts the values of PMU_FORMAT_ATTR(configid) and PMU_FORMAT_ATTR(preset) + * in the perf attributes defined in coresight-etm-perf.c. + * configid uses bits 63:32 of attr->config2, preset uses bits 3:0 of attr->config. + */ + if (attr->config2 & GENMASK_ULL(63, 32)) { + cfg_id = (u32)(attr->config2 >> 32); + preset = attr->config & 0xF; + ret = cscfg_csdev_enable_config(csdev, cfg_id, preset); + } + out: return ret; } @@ -400,7 +418,7 @@ static int etm4_enable_perf(struct coresight_device *csdev, }
/* Configure the tracer based on the session's specifics */ - ret = etm4_parse_event_config(drvdata, event); + ret = etm4_parse_event_config(csdev, event); if (ret) goto out; /* And enable it */ @@ -416,6 +434,8 @@ static int etm4_enable_sysfs(struct coresight_device *csdev) struct etm4_enable_arg arg = { }; int ret;
+ cscfg_csdev_set_enabled_feats(csdev); + spin_lock(&drvdata->spinlock);
/* @@ -530,11 +550,14 @@ static int etm4_disable_perf(struct coresight_device *csdev, u32 control; struct etm_filters *filters = event->hw.addr_filters; struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + struct perf_event_attr *attr = &event->attr;
if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) return -EINVAL;
etm4_disable_hw(drvdata); + if (attr->config2 & GENMASK_ULL(63, 32)) + cscfg_csdev_disable_config(csdev);
/* * Check if the start/stop logic was active when the unit was stopped. @@ -569,6 +592,7 @@ static void etm4_disable_sysfs(struct coresight_device *csdev) smp_call_function_single(drvdata->cpu, etm4_disable_hw, drvdata, 1);
spin_unlock(&drvdata->spinlock); + cscfg_csdev_save_enabled_feats(csdev); cpus_read_unlock();
dev_dbg(&csdev->dev, "ETM tracing disabled\n"); @@ -1536,6 +1560,13 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id) return ret; }
+ /* register with config infrastructure & load any current features */ + ret = etm4_cs_cfg_register(drvdata->csdev, dev_name(dev)); + if (ret) { + coresight_unregister(drvdata->csdev); + return ret; + } + etmdrvdata[drvdata->cpu] = drvdata;
pm_runtime_put(&adev->dev); @@ -1588,6 +1619,7 @@ static int __exit etm4_remove(struct amba_device *adev)
cpus_read_unlock();
+ cscfg_unregister_csdev(drvdata->csdev); coresight_unregister(drvdata->csdev);
return 0; diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c index 989ce7b8ade7..78e68f3032d5 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c @@ -9,6 +9,7 @@ #include <linux/sysfs.h> #include "coresight-etm4x.h" #include "coresight-priv.h" +#include "coresight-config.h"
static int etm4_set_mode_exclude(struct etmv4_drvdata *drvdata, bool exclude) { @@ -269,6 +270,8 @@ static ssize_t reset_store(struct device *dev,
spin_unlock(&drvdata->spinlock);
+ cscfg_csdev_reset_feats(to_coresight_device(dev)); + return size; } static DEVICE_ATTR_WO(reset);
On Fri, Oct 30, 2020 at 05:56:51PM +0000, Mike Leach wrote:
Adds in handlers to allow the ETMv4 to use the complex configuration support. Features and configurations can be loaded and selected in the device.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 3 +- .../hwtracing/coresight/coresight-etm4x-cfg.c | 181 ++++++++++++++++++ .../hwtracing/coresight/coresight-etm4x-cfg.h | 29 +++ .../coresight/coresight-etm4x-core.c | 36 +++- .../coresight/coresight-etm4x-sysfs.c | 3 + 5 files changed, 249 insertions(+), 3 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-etm4x-cfg.c create mode 100644 drivers/hwtracing/coresight/coresight-etm4x-cfg.h
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index daad9f103a78..ea544206204d 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -16,7 +16,8 @@ obj-$(CONFIG_CORESIGHT_SOURCE_ETM3X) += coresight-etm3x.o coresight-etm3x-y := coresight-etm3x-core.o coresight-etm-cp14.o \ coresight-etm3x-sysfs.o obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o -coresight-etm4x-y := coresight-etm4x-core.o coresight-etm4x-sysfs.o +coresight-etm4x-y := coresight-etm4x-core.o coresight-etm4x-sysfs.o \
coresight-etm4x-cfg.o
obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o obj-$(CONFIG_CORESIGHT_CPU_DEBUG) += coresight-cpu-debug.o obj-$(CONFIG_CORESIGHT_CATU) += coresight-catu.o diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c new file mode 100644 index 000000000000..9589d43e7947 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright(C) 2020 Linaro Limited. All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include "coresight-etm4x.h" +#include "coresight-etm4x-cfg.h" +#include "coresight-priv.h" +#include "coresight-syscfg.h"
+/**
- etm4_cfg_map_reg_offset - validate and map the register offset into a
location in the driver config struct.
- Limits the number of registers that can be accessed and programmed in
- features, to those which are used to control the trace capture parameters.
- Omits or limits access to those which the driver must use exclusively.
- Invalid offsets will result in fail code return and feature load failure.
- @drvdata: driver data to map into.
- @reg: register to map.
- @offset: device offset for the register
- */
+static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata,
struct cscfg_reg_csdev *reg, u32 offset)
+{
- int err = -EINVAL, idx;
- struct etmv4_config *drvcfg = &drvdata->config;
- u32 off_mask;
+#define CHECKREG(cval, elem) \
- { \
if (offset == cval) { \
reg->drv_store = &drvcfg->elem; \
err = 0; \
break; \
} \
- }
+#define CHECKREGIDX(cval, elem, off_idx) \
- { \
if (off_mask == cval) { \
reg->drv_store = &drvcfg->elem[off_idx]; \
err = 0; \
break; \
} \
- }
- if (((offset >= TRCEVENTCTL0R) && (offset <= TRCVIPCSSCTLR)) ||
((offset >= TRCSEQRSTEVR) && (offset <= TRCEXTINSELR)) ||
((offset >= TRCCIDCCTLR0) && (offset <= TRCVMIDCCTLR1))) {
do {
CHECKREG(TRCEVENTCTL0R, eventctrl0);
CHECKREG(TRCEVENTCTL1R, eventctrl1);
CHECKREG(TRCSTALLCTLR, stall_ctrl);
CHECKREG(TRCTSCTLR, ts_ctrl);
CHECKREG(TRCSYNCPR, syncfreq);
CHECKREG(TRCCCCTLR, ccctlr);
CHECKREG(TRCBBCTLR, bb_ctrl);
CHECKREG(TRCVICTLR, vinst_ctrl);
CHECKREG(TRCVIIECTLR, viiectlr);
CHECKREG(TRCVISSCTLR, vissctlr);
CHECKREG(TRCVIPCSSCTLR, vipcssctlr);
CHECKREG(TRCSEQRSTEVR, seq_rst);
CHECKREG(TRCSEQSTR, seq_state);
CHECKREG(TRCEXTINSELR, ext_inp);
CHECKREG(TRCCIDCCTLR0, ctxid_mask0);
CHECKREG(TRCCIDCCTLR1, ctxid_mask1);
CHECKREG(TRCVMIDCCTLR0, vmid_mask0);
CHECKREG(TRCVMIDCCTLR1, vmid_mask1);
} while (0);
- } else if ((offset & GENMASK(11, 4)) == TRCSEQEVRn(0)) {
/* sequencer state control registers */
idx = (offset & GENMASK(3, 0)) / 4;
if (idx < ETM_MAX_SEQ_STATES) {
reg->drv_store = &drvcfg->seq_ctrl[idx];
err = 0;
}
- } else if ((offset >= TRCSSCCRn(0)) && (offset <= TRCSSPCICRn(7))) {
/* 32 bit, 8 off indexed register sets */
idx = (offset & GENMASK(4, 0)) / 4;
off_mask = (offset & GENMASK(11, 5));
do {
CHECKREGIDX(TRCSSCCRn(0), ss_ctrl, idx);
CHECKREGIDX(TRCSSCSRn(0), ss_status, idx);
CHECKREGIDX(TRCSSPCICRn(0), ss_pe_cmp, idx);
This one is harder to understand because of @off_mask - please add it to the list of parameters to the marcro so that all the element needed to understand what is going on is at the same place.
} while (0);
- } else if ((offset >= TRCCIDCVRn(0)) && (offset <= TRCVMIDCVRn(7))) {
/* 64 bit, 8 off indexed register sets */
idx = (offset & GENMASK(5, 0)) / 8;
off_mask = (offset & GENMASK(11, 6));
do {
CHECKREGIDX(TRCCIDCVRn(0), ctxid_pid, idx);
CHECKREGIDX(TRCVMIDCVRn(0), vmid_val, idx);
} while (0);
- } else if ((offset >= TRCRSCTLRn(2)) &&
(offset <= TRCRSCTLRn((ETM_MAX_RES_SEL - 1)))) {
/* 32 bit resource selection regs, 32 off, skip fixed 0,1 */
idx = (offset & GENMASK(6, 0)) / 4;
if (idx < ETM_MAX_RES_SEL) {
reg->drv_store = &drvcfg->res_ctrl[idx];
err = 0;
}
- } else if ((offset >= TRCACVRn(0)) &&
(offset <= TRCACATRn((ETM_MAX_SINGLE_ADDR_CMP - 1)))) {
/* 64 bit addr cmp regs, 16 off */
idx = (offset & GENMASK(6, 0)) / 8;
off_mask = offset & GENMASK(11, 7);
do {
CHECKREGIDX(TRCACVRn(0), addr_val, idx);
CHECKREGIDX(TRCACATRn(0), addr_acc, idx);
} while (0);
- } else if ((offset >= TRCCNTRLDVRn(0)) &&
(offset <= TRCCNTVRn((ETMv4_MAX_CNTR - 1)))) {
/* 32 bit counter regs, 4 off (ETMv4_MAX_CNTR - 1) */
idx = (offset & GENMASK(3, 0)) / 4;
off_mask = offset & GENMASK(11, 4);
do {
CHECKREGIDX(TRCCNTRLDVRn(0), cntrldvr, idx);
CHECKREGIDX(TRCCNTCTLRn(0), cntr_ctrl, idx);
CHECKREGIDX(TRCCNTVRn(0), cntr_val, idx);
} while (0);
- }
- return err;
+}
+/**
- etm4_cfg_load_feature - load a feature into a device instance.
- @csdev: An ETMv4 CoreSight device.
- @feat: The feature to be loaded.
- The function will load a feature instance into the device, checking that
- the register definitions are valid for the device.
- Parameter and register definitions will be converted into internal
- structures that are used to set the values in the driver when the
- feature is enabled for the device.
- The feature spinlock pointer is initialised to the same spinlock
- that the driver uses to protect the internal register values.
- */
+static int etm4_cfg_load_feature(struct coresight_device *csdev,
struct cscfg_feature_csdev *feat)
+{
- struct device *dev = csdev->dev.parent;
- struct etmv4_drvdata *drvdata = dev_get_drvdata(dev);
- const struct cscfg_feature_desc *feat_desc = feat->desc;
- u32 offset;
- int i = 0, err = 0;
- /* essential we set the device spinlock */
Please explain why you are doing this. Otherwise we know it has to be done but still wonder about the motivation.
- feat->csdev_spinlock = &drvdata->spinlock;
- /* process the register descriptions */
- for (i = 0; i < feat->nr_regs && !err; i++) {
offset = feat_desc->regs[i].flags & CS_CFG_REG_ID_MASK;
This confirms my comment from a previous patch. Embedding the offset in a variable called "flags" is very confusing.
err = etm4_cfg_map_reg_offset(drvdata, &feat->regs[i], offset);
- }
- return err;
+}
+/* match information when loading configurations */ +#define CS_CFG_ETM4_MATCH_FLAGS (CS_CFG_MATCH_CLASS_SRC_ALL | \
CS_CFG_MATCH_CLASS_SRC_ETM4)
+int etm4_cs_cfg_register(struct coresight_device *csdev, const char *dev_name) +{
s/etm4_cs_cfg_register/etm4_cscfg_register()
- struct cscfg_match_info cfg_info;
- struct cscfg_csdev_feat_ops ops;
- cfg_info.dev_name = dev_name;
- cfg_info.match_flags = CS_CFG_ETM4_MATCH_FLAGS;
- ops.load_feat = &etm4_cfg_load_feature;
- return cscfg_register_csdev(csdev, &cfg_info, &ops);
+} diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.h b/drivers/hwtracing/coresight/coresight-etm4x-cfg.h new file mode 100644 index 000000000000..bf33c720b5e9 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
- */
+#ifndef _CORESIGHT_CORESIGHT_ETM4X_CFG_H +#define _CORESIGHT_CORESIGHT_ETM4X_CFG_H
+#include "coresight-config.h" +#include "coresight-etm4x.h"
+/* ETMv4 specific config defines */
+/* resource IDs */
+#define ETM4_CFG_RES_CTR 0x00001000 +#define ETM4_CFG_RES_CMP 0x00002000 +#define ETM4_CFG_RES_CMP_PAIR0 0x00003000 +#define ETM4_CFG_RES_CMP_PAIR1 0x00004000 +#define ETM4_CFG_RES_SEL 0x00005000 +#define ETM4_CFG_RES_SEL_PAIR0 0x00006000 +#define ETM4_CFG_RES_SEL_PAIR1 0x00007000 +#define ETM4_CFG_RES_SEQ 0x00008000 +#define ETM4_CFG_RES_TS 0x00009000 +#define ETM4_CFG_RES_MASK 0x0000F000
The first #define is used in the next patch but none of the others are.
+int etm4_cs_cfg_register(struct coresight_device *csdev, const char *dev_name);
+#endif /* _CORESIGHT_CORESIGHT_ETM4X_CFG_H */ diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 6096d7abf80d..88213aa7a72e 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -34,6 +34,8 @@ #include "coresight-etm4x.h" #include "coresight-etm-perf.h" +#include "coresight-etm4x-cfg.h" +#include "coresight-syscfg.h" static int boot_enable; module_param(boot_enable, int, 0444); @@ -321,12 +323,15 @@ static int etm4_config_timestamp_event(struct etmv4_drvdata *drvdata) return ret; } -static int etm4_parse_event_config(struct etmv4_drvdata *drvdata, +static int etm4_parse_event_config(struct coresight_device *csdev, struct perf_event *event) { int ret = 0;
- struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); struct etmv4_config *config = &drvdata->config; struct perf_event_attr *attr = &event->attr;
- unsigned long cfg_id;
- int preset;
if (!attr) { ret = -EINVAL; @@ -384,6 +389,19 @@ static int etm4_parse_event_config(struct etmv4_drvdata *drvdata, /* bit[12], Return stack enable bit */ config->cfg |= BIT(12);
- /*
* Set any selected configuration and preset.
*
* This extracts the values of PMU_FORMAT_ATTR(configid) and PMU_FORMAT_ATTR(preset)
* in the perf attributes defined in coresight-etm-perf.c.
* configid uses bits 63:32 of attr->config2, preset uses bits 3:0 of attr->config.
*/
- if (attr->config2 & GENMASK_ULL(63, 32)) {
I understand why you have used a mask of 63-32 but it would be extremely cryptic for anyone else. Please add a comment that justify your choice.
cfg_id = (u32)(attr->config2 >> 32);
preset = attr->config & 0xF;
This implies that presets need to start at 1 rather than 0. Otherwise there is no way to specify the absence of a preset. There is a comment for cscfg_csdev_enable_config() but adding another one here to complete the equation would be appreciated.
ret = cscfg_csdev_enable_config(csdev, cfg_id, preset);
- }
out: return ret; } @@ -400,7 +418,7 @@ static int etm4_enable_perf(struct coresight_device *csdev, } /* Configure the tracer based on the session's specifics */
- ret = etm4_parse_event_config(drvdata, event);
- ret = etm4_parse_event_config(csdev, event); if (ret) goto out; /* And enable it */
@@ -416,6 +434,8 @@ static int etm4_enable_sysfs(struct coresight_device *csdev) struct etm4_enable_arg arg = { }; int ret;
- cscfg_csdev_set_enabled_feats(csdev);
- spin_lock(&drvdata->spinlock);
/* @@ -530,11 +550,14 @@ static int etm4_disable_perf(struct coresight_device *csdev, u32 control; struct etm_filters *filters = event->hw.addr_filters; struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- struct perf_event_attr *attr = &event->attr;
if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) return -EINVAL; etm4_disable_hw(drvdata);
- if (attr->config2 & GENMASK_ULL(63, 32))
Here too.
I will continue tomorrow.
Thanks, Mathieu
cscfg_csdev_disable_config(csdev);
/* * Check if the start/stop logic was active when the unit was stopped. @@ -569,6 +592,7 @@ static void etm4_disable_sysfs(struct coresight_device *csdev) smp_call_function_single(drvdata->cpu, etm4_disable_hw, drvdata, 1); spin_unlock(&drvdata->spinlock);
- cscfg_csdev_save_enabled_feats(csdev); cpus_read_unlock();
dev_dbg(&csdev->dev, "ETM tracing disabled\n"); @@ -1536,6 +1560,13 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id) return ret; }
- /* register with config infrastructure & load any current features */
- ret = etm4_cs_cfg_register(drvdata->csdev, dev_name(dev));
- if (ret) {
coresight_unregister(drvdata->csdev);
return ret;
- }
- etmdrvdata[drvdata->cpu] = drvdata;
pm_runtime_put(&adev->dev); @@ -1588,6 +1619,7 @@ static int __exit etm4_remove(struct amba_device *adev) cpus_read_unlock();
- cscfg_unregister_csdev(drvdata->csdev); coresight_unregister(drvdata->csdev);
return 0; diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c index 989ce7b8ade7..78e68f3032d5 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c @@ -9,6 +9,7 @@ #include <linux/sysfs.h> #include "coresight-etm4x.h" #include "coresight-priv.h" +#include "coresight-config.h" static int etm4_set_mode_exclude(struct etmv4_drvdata *drvdata, bool exclude) { @@ -269,6 +270,8 @@ static ssize_t reset_store(struct device *dev, spin_unlock(&drvdata->spinlock);
- cscfg_csdev_reset_feats(to_coresight_device(dev));
- return size;
} static DEVICE_ATTR_WO(reset); -- 2.17.1
Hi Mathieu,
On Mon, 23 Nov 2020 at 21:58, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Fri, Oct 30, 2020 at 05:56:51PM +0000, Mike Leach wrote:
Adds in handlers to allow the ETMv4 to use the complex configuration support. Features and configurations can be loaded and selected in the device.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 3 +- .../hwtracing/coresight/coresight-etm4x-cfg.c | 181 ++++++++++++++++++ .../hwtracing/coresight/coresight-etm4x-cfg.h | 29 +++ .../coresight/coresight-etm4x-core.c | 36 +++- .../coresight/coresight-etm4x-sysfs.c | 3 + 5 files changed, 249 insertions(+), 3 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-etm4x-cfg.c create mode 100644 drivers/hwtracing/coresight/coresight-etm4x-cfg.h
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index daad9f103a78..ea544206204d 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -16,7 +16,8 @@ obj-$(CONFIG_CORESIGHT_SOURCE_ETM3X) += coresight-etm3x.o coresight-etm3x-y := coresight-etm3x-core.o coresight-etm-cp14.o \ coresight-etm3x-sysfs.o obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o -coresight-etm4x-y := coresight-etm4x-core.o coresight-etm4x-sysfs.o +coresight-etm4x-y := coresight-etm4x-core.o coresight-etm4x-sysfs.o \
coresight-etm4x-cfg.o
obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o obj-$(CONFIG_CORESIGHT_CPU_DEBUG) += coresight-cpu-debug.o obj-$(CONFIG_CORESIGHT_CATU) += coresight-catu.o diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c new file mode 100644 index 000000000000..9589d43e7947 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright(C) 2020 Linaro Limited. All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include "coresight-etm4x.h" +#include "coresight-etm4x-cfg.h" +#include "coresight-priv.h" +#include "coresight-syscfg.h"
+/**
- etm4_cfg_map_reg_offset - validate and map the register offset into a
location in the driver config struct.
- Limits the number of registers that can be accessed and programmed in
- features, to those which are used to control the trace capture parameters.
- Omits or limits access to those which the driver must use exclusively.
- Invalid offsets will result in fail code return and feature load failure.
- @drvdata: driver data to map into.
- @reg: register to map.
- @offset: device offset for the register
- */
+static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata,
struct cscfg_reg_csdev *reg, u32 offset)
+{
int err = -EINVAL, idx;
struct etmv4_config *drvcfg = &drvdata->config;
u32 off_mask;
+#define CHECKREG(cval, elem) \
{ \
if (offset == cval) { \
reg->drv_store = &drvcfg->elem; \
err = 0; \
break; \
} \
}
+#define CHECKREGIDX(cval, elem, off_idx) \
{ \
if (off_mask == cval) { \
reg->drv_store = &drvcfg->elem[off_idx]; \
err = 0; \
break; \
} \
}
if (((offset >= TRCEVENTCTL0R) && (offset <= TRCVIPCSSCTLR)) ||
((offset >= TRCSEQRSTEVR) && (offset <= TRCEXTINSELR)) ||
((offset >= TRCCIDCCTLR0) && (offset <= TRCVMIDCCTLR1))) {
do {
CHECKREG(TRCEVENTCTL0R, eventctrl0);
CHECKREG(TRCEVENTCTL1R, eventctrl1);
CHECKREG(TRCSTALLCTLR, stall_ctrl);
CHECKREG(TRCTSCTLR, ts_ctrl);
CHECKREG(TRCSYNCPR, syncfreq);
CHECKREG(TRCCCCTLR, ccctlr);
CHECKREG(TRCBBCTLR, bb_ctrl);
CHECKREG(TRCVICTLR, vinst_ctrl);
CHECKREG(TRCVIIECTLR, viiectlr);
CHECKREG(TRCVISSCTLR, vissctlr);
CHECKREG(TRCVIPCSSCTLR, vipcssctlr);
CHECKREG(TRCSEQRSTEVR, seq_rst);
CHECKREG(TRCSEQSTR, seq_state);
CHECKREG(TRCEXTINSELR, ext_inp);
CHECKREG(TRCCIDCCTLR0, ctxid_mask0);
CHECKREG(TRCCIDCCTLR1, ctxid_mask1);
CHECKREG(TRCVMIDCCTLR0, vmid_mask0);
CHECKREG(TRCVMIDCCTLR1, vmid_mask1);
} while (0);
} else if ((offset & GENMASK(11, 4)) == TRCSEQEVRn(0)) {
/* sequencer state control registers */
idx = (offset & GENMASK(3, 0)) / 4;
if (idx < ETM_MAX_SEQ_STATES) {
reg->drv_store = &drvcfg->seq_ctrl[idx];
err = 0;
}
} else if ((offset >= TRCSSCCRn(0)) && (offset <= TRCSSPCICRn(7))) {
/* 32 bit, 8 off indexed register sets */
idx = (offset & GENMASK(4, 0)) / 4;
off_mask = (offset & GENMASK(11, 5));
do {
CHECKREGIDX(TRCSSCCRn(0), ss_ctrl, idx);
CHECKREGIDX(TRCSSCSRn(0), ss_status, idx);
CHECKREGIDX(TRCSSPCICRn(0), ss_pe_cmp, idx);
This one is harder to understand because of @off_mask - please add it to the list of parameters to the marcro so that all the element needed to understand what is going on is at the same place.
OK
} while (0);
} else if ((offset >= TRCCIDCVRn(0)) && (offset <= TRCVMIDCVRn(7))) {
/* 64 bit, 8 off indexed register sets */
idx = (offset & GENMASK(5, 0)) / 8;
off_mask = (offset & GENMASK(11, 6));
do {
CHECKREGIDX(TRCCIDCVRn(0), ctxid_pid, idx);
CHECKREGIDX(TRCVMIDCVRn(0), vmid_val, idx);
} while (0);
} else if ((offset >= TRCRSCTLRn(2)) &&
(offset <= TRCRSCTLRn((ETM_MAX_RES_SEL - 1)))) {
/* 32 bit resource selection regs, 32 off, skip fixed 0,1 */
idx = (offset & GENMASK(6, 0)) / 4;
if (idx < ETM_MAX_RES_SEL) {
reg->drv_store = &drvcfg->res_ctrl[idx];
err = 0;
}
} else if ((offset >= TRCACVRn(0)) &&
(offset <= TRCACATRn((ETM_MAX_SINGLE_ADDR_CMP - 1)))) {
/* 64 bit addr cmp regs, 16 off */
idx = (offset & GENMASK(6, 0)) / 8;
off_mask = offset & GENMASK(11, 7);
do {
CHECKREGIDX(TRCACVRn(0), addr_val, idx);
CHECKREGIDX(TRCACATRn(0), addr_acc, idx);
} while (0);
} else if ((offset >= TRCCNTRLDVRn(0)) &&
(offset <= TRCCNTVRn((ETMv4_MAX_CNTR - 1)))) {
/* 32 bit counter regs, 4 off (ETMv4_MAX_CNTR - 1) */
idx = (offset & GENMASK(3, 0)) / 4;
off_mask = offset & GENMASK(11, 4);
do {
CHECKREGIDX(TRCCNTRLDVRn(0), cntrldvr, idx);
CHECKREGIDX(TRCCNTCTLRn(0), cntr_ctrl, idx);
CHECKREGIDX(TRCCNTVRn(0), cntr_val, idx);
} while (0);
}
return err;
+}
+/**
- etm4_cfg_load_feature - load a feature into a device instance.
- @csdev: An ETMv4 CoreSight device.
- @feat: The feature to be loaded.
- The function will load a feature instance into the device, checking that
- the register definitions are valid for the device.
- Parameter and register definitions will be converted into internal
- structures that are used to set the values in the driver when the
- feature is enabled for the device.
- The feature spinlock pointer is initialised to the same spinlock
- that the driver uses to protect the internal register values.
- */
+static int etm4_cfg_load_feature(struct coresight_device *csdev,
struct cscfg_feature_csdev *feat)
+{
struct device *dev = csdev->dev.parent;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev);
const struct cscfg_feature_desc *feat_desc = feat->desc;
u32 offset;
int i = 0, err = 0;
/* essential we set the device spinlock */
Please explain why you are doing this. Otherwise we know it has to be done but still wonder about the motivation.
Agreed.
feat->csdev_spinlock = &drvdata->spinlock;
/* process the register descriptions */
for (i = 0; i < feat->nr_regs && !err; i++) {
offset = feat_desc->regs[i].flags & CS_CFG_REG_ID_MASK;
This confirms my comment from a previous patch. Embedding the offset in a variable called "flags" is very confusing.
err = etm4_cfg_map_reg_offset(drvdata, &feat->regs[i], offset);
}
return err;
+}
+/* match information when loading configurations */ +#define CS_CFG_ETM4_MATCH_FLAGS (CS_CFG_MATCH_CLASS_SRC_ALL | \
CS_CFG_MATCH_CLASS_SRC_ETM4)
+int etm4_cs_cfg_register(struct coresight_device *csdev, const char *dev_name) +{
s/etm4_cs_cfg_register/etm4_cscfg_register()
struct cscfg_match_info cfg_info;
struct cscfg_csdev_feat_ops ops;
cfg_info.dev_name = dev_name;
cfg_info.match_flags = CS_CFG_ETM4_MATCH_FLAGS;
ops.load_feat = &etm4_cfg_load_feature;
return cscfg_register_csdev(csdev, &cfg_info, &ops);
+} diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.h b/drivers/hwtracing/coresight/coresight-etm4x-cfg.h new file mode 100644 index 000000000000..bf33c720b5e9 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
- */
+#ifndef _CORESIGHT_CORESIGHT_ETM4X_CFG_H +#define _CORESIGHT_CORESIGHT_ETM4X_CFG_H
+#include "coresight-config.h" +#include "coresight-etm4x.h"
+/* ETMv4 specific config defines */
+/* resource IDs */
+#define ETM4_CFG_RES_CTR 0x00001000 +#define ETM4_CFG_RES_CMP 0x00002000 +#define ETM4_CFG_RES_CMP_PAIR0 0x00003000 +#define ETM4_CFG_RES_CMP_PAIR1 0x00004000 +#define ETM4_CFG_RES_SEL 0x00005000 +#define ETM4_CFG_RES_SEL_PAIR0 0x00006000 +#define ETM4_CFG_RES_SEL_PAIR1 0x00007000 +#define ETM4_CFG_RES_SEQ 0x00008000 +#define ETM4_CFG_RES_TS 0x00009000 +#define ETM4_CFG_RES_MASK 0x0000F000
The first #define is used in the next patch but none of the others are.
Could drop them for the initial set. however - they are needed to allow users to define their own features. Will re-introduce in the follow-up set that targets ETMv4 resource management and device programming. Ultimately there will be some elements that may not be used in the examples / immediate source that are needed for the complete solution, and can be used in user configurations.
+int etm4_cs_cfg_register(struct coresight_device *csdev, const char *dev_name);
+#endif /* _CORESIGHT_CORESIGHT_ETM4X_CFG_H */ diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 6096d7abf80d..88213aa7a72e 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -34,6 +34,8 @@
#include "coresight-etm4x.h" #include "coresight-etm-perf.h" +#include "coresight-etm4x-cfg.h" +#include "coresight-syscfg.h"
static int boot_enable; module_param(boot_enable, int, 0444); @@ -321,12 +323,15 @@ static int etm4_config_timestamp_event(struct etmv4_drvdata *drvdata) return ret; }
-static int etm4_parse_event_config(struct etmv4_drvdata *drvdata, +static int etm4_parse_event_config(struct coresight_device *csdev, struct perf_event *event) { int ret = 0;
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); struct etmv4_config *config = &drvdata->config; struct perf_event_attr *attr = &event->attr;
unsigned long cfg_id;
int preset; if (!attr) { ret = -EINVAL;
@@ -384,6 +389,19 @@ static int etm4_parse_event_config(struct etmv4_drvdata *drvdata, /* bit[12], Return stack enable bit */ config->cfg |= BIT(12);
/*
* Set any selected configuration and preset.
*
* This extracts the values of PMU_FORMAT_ATTR(configid) and PMU_FORMAT_ATTR(preset)
* in the perf attributes defined in coresight-etm-perf.c.
* configid uses bits 63:32 of attr->config2, preset uses bits 3:0 of attr->config.
*/
if (attr->config2 & GENMASK_ULL(63, 32)) {
I understand why you have used a mask of 63-32 but it would be extremely cryptic for anyone else. Please add a comment that justify your choice.
cfg_id = (u32)(attr->config2 >> 32);
preset = attr->config & 0xF;
This implies that presets need to start at 1 rather than 0. Otherwise there is no way to specify the absence of a preset. There is a comment for cscfg_csdev_enable_config() but adding another one here to complete the equation would be appreciated.
This is true - presets start at index 1, preset 0 is the current set of values in configfs. Preset 0 is used to allow immediate setting of parameter values.
ret = cscfg_csdev_enable_config(csdev, cfg_id, preset);
}
out: return ret; } @@ -400,7 +418,7 @@ static int etm4_enable_perf(struct coresight_device *csdev, }
/* Configure the tracer based on the session's specifics */
ret = etm4_parse_event_config(drvdata, event);
ret = etm4_parse_event_config(csdev, event); if (ret) goto out; /* And enable it */
@@ -416,6 +434,8 @@ static int etm4_enable_sysfs(struct coresight_device *csdev) struct etm4_enable_arg arg = { }; int ret;
cscfg_csdev_set_enabled_feats(csdev);
spin_lock(&drvdata->spinlock); /*
@@ -530,11 +550,14 @@ static int etm4_disable_perf(struct coresight_device *csdev, u32 control; struct etm_filters *filters = event->hw.addr_filters; struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
struct perf_event_attr *attr = &event->attr; if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) return -EINVAL; etm4_disable_hw(drvdata);
if (attr->config2 & GENMASK_ULL(63, 32))
Here too.
I will continue tomorrow.
Thanks, Mathieu
cscfg_csdev_disable_config(csdev); /* * Check if the start/stop logic was active when the unit was stopped.
@@ -569,6 +592,7 @@ static void etm4_disable_sysfs(struct coresight_device *csdev) smp_call_function_single(drvdata->cpu, etm4_disable_hw, drvdata, 1);
spin_unlock(&drvdata->spinlock);
cscfg_csdev_save_enabled_feats(csdev); cpus_read_unlock(); dev_dbg(&csdev->dev, "ETM tracing disabled\n");
@@ -1536,6 +1560,13 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id) return ret; }
/* register with config infrastructure & load any current features */
ret = etm4_cs_cfg_register(drvdata->csdev, dev_name(dev));
if (ret) {
coresight_unregister(drvdata->csdev);
return ret;
}
etmdrvdata[drvdata->cpu] = drvdata; pm_runtime_put(&adev->dev);
@@ -1588,6 +1619,7 @@ static int __exit etm4_remove(struct amba_device *adev)
cpus_read_unlock();
cscfg_unregister_csdev(drvdata->csdev); coresight_unregister(drvdata->csdev); return 0;
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c index 989ce7b8ade7..78e68f3032d5 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c @@ -9,6 +9,7 @@ #include <linux/sysfs.h> #include "coresight-etm4x.h" #include "coresight-priv.h" +#include "coresight-config.h"
static int etm4_set_mode_exclude(struct etmv4_drvdata *drvdata, bool exclude) { @@ -269,6 +270,8 @@ static ssize_t reset_store(struct device *dev,
spin_unlock(&drvdata->spinlock);
cscfg_csdev_reset_feats(to_coresight_device(dev));
return size;
} static DEVICE_ATTR_WO(reset); -- 2.17.1
Thanks
Mike
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
Preload set of configurations.
This patch creates a small set of preloaded configurations and features that are available immediately after coresight has been initialised.
The current set provides a strobing feature for ETMv4, that creates a periodic sampling of trace by switching trace generation on and off using counters in the ETM.
A configuration called "autofdo" is also provided that uses the 'strobing' feature and provides a couple of preset values, selectable on the perf command line.
Signed-off-by: Mike Leach mike.leach@linaro.org --- drivers/hwtracing/coresight/Makefile | 3 +- .../coresight/coresight-cfg-preload.c | 160 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-core.c | 6 + .../hwtracing/coresight/coresight-syscfg.h | 1 + 4 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 drivers/hwtracing/coresight/coresight-cfg-preload.c
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index ea544206204d..9de5586cfd1a 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -4,7 +4,8 @@ # obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \ - coresight-sysfs.o coresight-syscfg.o coresight-config.o + coresight-sysfs.o coresight-syscfg.o coresight-config.o \ + coresight-cfg-preload.o obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-cfg-preload.c b/drivers/hwtracing/coresight/coresight-cfg-preload.c new file mode 100644 index 000000000000..0975d64a1d9e --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cfg-preload.c @@ -0,0 +1,160 @@ +// 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" +#include "coresight-etm4x-cfg.h" + +/* preload configurations and features */ + +/* preload in features for ETMv4 */ + +/* strobe feature */ + +/* register defines */ +#define STRB_REG_CTR (CS_CFG_REG_RESOURCE | ETM4_CFG_RES_CTR) +#define STRB_REG_CTR_RB (STRB_REG_CTR | CS_CFG_REG_VAL_SAVE) +#define STRB_REG_CTR_PRM (STRB_REG_CTR | CS_CFG_REG_VAL_PARAM) +#define STRB_REG_SEQ (CS_CFG_REG_RESOURCE | ETM4_CFG_RES_SEQ) +#define STRB_REG_SEL (CS_CFG_REG_RESOURCE | ETM4_CFG_RES_SEL) +#define STRB_REG_VI (CS_CFG_REG_STD | CS_CFG_REG_VAL_MASK) + +static struct cscfg_parameter_desc strobe_params[] = { + { + .name = "window", + .value = 5000, + }, + { + .name = "period", + .value = 10000, + }, +}; + +static struct cscfg_regval strobe_regs[] = { + /* resource selectors */ + { + .flags = STRB_REG_SEL | TRCRSCTLRn(2), + .val32 = 0x20001, + }, + { + .flags = STRB_REG_SEQ | TRCRSCTLRn(3), + .val32 = 0x20002, + }, + /* strobe window counter 0 - reload from param 0 */ + { + .flags = STRB_REG_CTR_RB | TRCCNTVRn(0), + }, + { + .flags = STRB_REG_CTR_PRM | TRCCNTRLDVRn(0), + .val32 = 0, + }, + { + .flags = STRB_REG_CTR | TRCCNTCTLRn(0), + .val32 = 0x10001, + }, + /* strobe period counter 1 - reload from param 1 */ + { + .flags = STRB_REG_CTR_RB | TRCCNTVRn(1), + }, + { + .flags = STRB_REG_CTR_PRM | TRCCNTRLDVRn(1), + .val32 = 1, + }, + { + .flags = STRB_REG_CTR | TRCCNTCTLRn(1), + .val32 = 0x8102, + }, + /* sequencer */ + { + .flags = STRB_REG_SEQ | TRCSEQEVRn(0), + .val32 = 0x0081, + }, + { + .flags = STRB_REG_SEQ | TRCSEQEVRn(1), + .val32 = 0x0000, + }, + /* view-inst */ + { + .flags = STRB_REG_VI | TRCVICTLR, + .val32 = 0x0003, + .mask32 = 0x0003, + }, + /* end of regs */ +}; + +static struct cscfg_feature_desc strobe = { + .name = "strobing", + .brief = "Generate periodic trace capture windows.\n" + "parameter 'window': a number of CPU cycles (W)\n" + "parameter 'period': trace enabled for W cycles every period x W cycles\n", + .match_flags = CS_CFG_MATCH_CLASS_SRC_ETM4, + .nr_params = ARRAY_SIZE(strobe_params), + .params = strobe_params, + .nr_regs = ARRAY_SIZE(strobe_regs), + .regs = strobe_regs, +}; + +static struct cscfg_feature_desc *preload_feats[] = { + &strobe, + 0 +}; + +/* create an autofdo configuration */ + +/* we will provide 9 sets of preset parameter values */ +#define AFDO_NR_PRESETS 9 +/* the total number of parameters in used features */ +#define AFDO_NR_PARAM_SUM ARRAY_SIZE(strobe_params) + +#define AFDO_MATCH_STROBING (CS_CFG_MATCH_INST_ANY | CS_CFG_MATCH_CLASS_SRC_ETM4) + +static struct cscfg_config_feat_ref afdo_refs[] = { + { + .name = "strobing", + .nr_params = ARRAY_SIZE(strobe_params), + .match = { + .match_flags = AFDO_MATCH_STROBING, + }, + }, +}; + +/* + * set of presets leaves strobing window constant while varying period to allow + * experimentation with mark / space ratios for various workloads + */ +static u64 afdo_presets[AFDO_NR_PRESETS][AFDO_NR_PARAM_SUM] = { + { 5000, 2 }, + { 5000, 4 }, + { 5000, 8 }, + { 5000, 16 }, + { 5000, 64 }, + { 5000, 128 }, + { 5000, 512 }, + { 5000, 1024 }, + { 5000, 4096 }, +}; + +static struct cscfg_config_desc afdo = { + .name = "autofdo", + .brief = "Setup ETMs with strobing for autofdo\n" + "Supplied presets allow experimentation with mark-space ratio for various loads\n", + .nr_refs = ARRAY_SIZE(afdo_refs), + .refs = afdo_refs, + .nr_presets = AFDO_NR_PRESETS, + .nr_total_params = AFDO_NR_PARAM_SUM, + .presets = &afdo_presets[0][0], +}; + +static struct cscfg_config_desc *preload_cfgs[] = { + &afdo, + 0 +}; + +/* preload called with mutex locked */ +int cscfg_preload(void) +{ + return cscfg_load_config_sets(preload_cfgs, preload_feats); +} diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 481d2b7b6b6f..dca84b3f5fca 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -1680,9 +1680,15 @@ static int __init coresight_init(void)
/* initialise the coresight syscfg API */ ret = cscfg_init(); + if (ret) + goto exit_perf_close; + + /* preload builtin configurations */ + ret = cscfg_preload(); if (!ret) return 0;
+exit_perf_close: etm_perf_exit(); exit_bus_unregister: bus_unregister(&coresight_bustype); diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index ecf4aac7d712..e8f352599dd7 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -45,6 +45,7 @@ struct cscfg_csdev_register { /* internal core operations for cscfg */ int __init cscfg_init(void); void __exit cscfg_exit(void); +int cscfg_preload(void);
/* syscfg external API */ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs,
On Fri, Oct 30, 2020 at 05:56:52PM +0000, Mike Leach wrote:
Preload set of configurations.
This patch creates a small set of preloaded configurations and features that are available immediately after coresight has been initialised.
The current set provides a strobing feature for ETMv4, that creates a periodic sampling of trace by switching trace generation on and off using counters in the ETM.
A configuration called "autofdo" is also provided that uses the 'strobing' feature and provides a couple of preset values, selectable on the perf command line.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 3 +- .../coresight/coresight-cfg-preload.c | 160 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-core.c | 6 + .../hwtracing/coresight/coresight-syscfg.h | 1 + 4 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 drivers/hwtracing/coresight/coresight-cfg-preload.c
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index ea544206204d..9de5586cfd1a 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -4,7 +4,8 @@ # obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \
coresight-sysfs.o coresight-syscfg.o coresight-config.o
coresight-sysfs.o coresight-syscfg.o coresight-config.o \
coresight-cfg-preload.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-cfg-preload.c b/drivers/hwtracing/coresight/coresight-cfg-preload.c new file mode 100644 index 000000000000..0975d64a1d9e --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cfg-preload.c
I think there needs to be a separation between the function of preloading configurations and the preconfigurations themselves. Ultimately having one .c file for each preconfiguration would be optimal. That will open the way for a future feature where users get to select which preconfiguration they want to see included.
@@ -0,0 +1,160 @@ +// 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" +#include "coresight-etm4x-cfg.h"
+/* preload configurations and features */
+/* preload in features for ETMv4 */
+/* strobe feature */
+/* register defines */ +#define STRB_REG_CTR (CS_CFG_REG_RESOURCE | ETM4_CFG_RES_CTR) +#define STRB_REG_CTR_RB (STRB_REG_CTR | CS_CFG_REG_VAL_SAVE) +#define STRB_REG_CTR_PRM (STRB_REG_CTR | CS_CFG_REG_VAL_PARAM) +#define STRB_REG_SEQ (CS_CFG_REG_RESOURCE | ETM4_CFG_RES_SEQ) +#define STRB_REG_SEL (CS_CFG_REG_RESOURCE | ETM4_CFG_RES_SEL) +#define STRB_REG_VI (CS_CFG_REG_STD | CS_CFG_REG_VAL_MASK)
This is the 3rd iteration of this set that I review. Along the way I have come to understand most of the things that are presented. The above and all the information packed in .flags is one concept that did not get better as time went by. I have already remarked on the need to split the register address from the flags themselves. I think the remaining flags need further simplification.
Either some options are removed or a different way to present the information is required. Otherwise I fear people will not be able to write their own preconfigurations.
+static struct cscfg_parameter_desc strobe_params[] = {
- {
.name = "window",
.value = 5000,
- },
- {
.name = "period",
.value = 10000,
- },
+};
+static struct cscfg_regval strobe_regs[] = {
- /* resource selectors */
- {
.flags = STRB_REG_SEL | TRCRSCTLRn(2),
.val32 = 0x20001,
- },
- {
.flags = STRB_REG_SEQ | TRCRSCTLRn(3),
.val32 = 0x20002,
- },
- /* strobe window counter 0 - reload from param 0 */
- {
.flags = STRB_REG_CTR_RB | TRCCNTVRn(0),
- },
- {
.flags = STRB_REG_CTR_PRM | TRCCNTRLDVRn(0),
.val32 = 0,
- },
- {
.flags = STRB_REG_CTR | TRCCNTCTLRn(0),
.val32 = 0x10001,
- },
- /* strobe period counter 1 - reload from param 1 */
- {
.flags = STRB_REG_CTR_RB | TRCCNTVRn(1),
- },
- {
.flags = STRB_REG_CTR_PRM | TRCCNTRLDVRn(1),
.val32 = 1,
- },
- {
.flags = STRB_REG_CTR | TRCCNTCTLRn(1),
.val32 = 0x8102,
- },
- /* sequencer */
- {
.flags = STRB_REG_SEQ | TRCSEQEVRn(0),
.val32 = 0x0081,
- },
- {
.flags = STRB_REG_SEQ | TRCSEQEVRn(1),
.val32 = 0x0000,
- },
- /* view-inst */
- {
.flags = STRB_REG_VI | TRCVICTLR,
.val32 = 0x0003,
.mask32 = 0x0003,
- },
- /* end of regs */
+};
+static struct cscfg_feature_desc strobe = {
- .name = "strobing",
- .brief = "Generate periodic trace capture windows.\n"
- "parameter 'window': a number of CPU cycles (W)\n"
- "parameter 'period': trace enabled for W cycles every period x W cycles\n",
- .match_flags = CS_CFG_MATCH_CLASS_SRC_ETM4,
- .nr_params = ARRAY_SIZE(strobe_params),
- .params = strobe_params,
- .nr_regs = ARRAY_SIZE(strobe_regs),
- .regs = strobe_regs,
+};
+static struct cscfg_feature_desc *preload_feats[] = {
- &strobe,
- 0
+};
+/* create an autofdo configuration */
+/* we will provide 9 sets of preset parameter values */ +#define AFDO_NR_PRESETS 9 +/* the total number of parameters in used features */ +#define AFDO_NR_PARAM_SUM ARRAY_SIZE(strobe_params)
+#define AFDO_MATCH_STROBING (CS_CFG_MATCH_INST_ANY | CS_CFG_MATCH_CLASS_SRC_ETM4)
+static struct cscfg_config_feat_ref afdo_refs[] = {
- {
.name = "strobing",
.nr_params = ARRAY_SIZE(strobe_params),
.match = {
.match_flags = AFDO_MATCH_STROBING,
},
- },
+};
+/*
- set of presets leaves strobing window constant while varying period to allow
- experimentation with mark / space ratios for various workloads
- */
+static u64 afdo_presets[AFDO_NR_PRESETS][AFDO_NR_PARAM_SUM] = {
- { 5000, 2 },
- { 5000, 4 },
- { 5000, 8 },
- { 5000, 16 },
- { 5000, 64 },
- { 5000, 128 },
- { 5000, 512 },
- { 5000, 1024 },
- { 5000, 4096 },
+};
+static struct cscfg_config_desc afdo = {
- .name = "autofdo",
- .brief = "Setup ETMs with strobing for autofdo\n"
- "Supplied presets allow experimentation with mark-space ratio for various loads\n",
- .nr_refs = ARRAY_SIZE(afdo_refs),
- .refs = afdo_refs,
- .nr_presets = AFDO_NR_PRESETS,
- .nr_total_params = AFDO_NR_PARAM_SUM,
- .presets = &afdo_presets[0][0],
+};
The current layout works if we have a single preconfiguration but doesn't scale as soon as we need to add a new one. I think the above should be in coresight-afdo.c. That way other preconfiguration can be added to preload_cfgs[] without modifying anything else than the array declaration itself.
+static struct cscfg_config_desc *preload_cfgs[] = {
- &afdo,
- 0
+};
+/* preload called with mutex locked */ +int cscfg_preload(void) +{
- return cscfg_load_config_sets(preload_cfgs, preload_feats);
+} diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 481d2b7b6b6f..dca84b3f5fca 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -1680,9 +1680,15 @@ static int __init coresight_init(void) /* initialise the coresight syscfg API */ ret = cscfg_init();
- if (ret)
goto exit_perf_close;
- /* preload builtin configurations */
- ret = cscfg_preload(); if (!ret) return 0;
+exit_perf_close: etm_perf_exit(); exit_bus_unregister: bus_unregister(&coresight_bustype); diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index ecf4aac7d712..e8f352599dd7 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -45,6 +45,7 @@ struct cscfg_csdev_register { /* internal core operations for cscfg */ int __init cscfg_init(void); void __exit cscfg_exit(void); +int cscfg_preload(void); /* syscfg external API */ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, -- 2.17.1
Hi Mathieu,
On Tue, 24 Nov 2020 at 17:51, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Fri, Oct 30, 2020 at 05:56:52PM +0000, Mike Leach wrote:
Preload set of configurations.
This patch creates a small set of preloaded configurations and features that are available immediately after coresight has been initialised.
The current set provides a strobing feature for ETMv4, that creates a periodic sampling of trace by switching trace generation on and off using counters in the ETM.
A configuration called "autofdo" is also provided that uses the 'strobing' feature and provides a couple of preset values, selectable on the perf command line.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 3 +- .../coresight/coresight-cfg-preload.c | 160 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-core.c | 6 + .../hwtracing/coresight/coresight-syscfg.h | 1 + 4 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 drivers/hwtracing/coresight/coresight-cfg-preload.c
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index ea544206204d..9de5586cfd1a 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -4,7 +4,8 @@ # obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \
coresight-sysfs.o coresight-syscfg.o coresight-config.o
coresight-sysfs.o coresight-syscfg.o coresight-config.o \
coresight-cfg-preload.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-cfg-preload.c b/drivers/hwtracing/coresight/coresight-cfg-preload.c new file mode 100644 index 000000000000..0975d64a1d9e --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cfg-preload.c
I think there needs to be a separation between the function of preloading configurations and the preconfigurations themselves. Ultimately having one .c file for each preconfiguration would be optimal. That will open the way for a future feature where users get to select which preconfiguration they want to see included.
I think that the preloaded configs are going to be the exception rather than the rule. The follow up sets will allow dynamic loading of configurations, via loadable module or configfs. This is the way people get what they want.
@@ -0,0 +1,160 @@ +// 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" +#include "coresight-etm4x-cfg.h"
+/* preload configurations and features */
+/* preload in features for ETMv4 */
+/* strobe feature */
+/* register defines */ +#define STRB_REG_CTR (CS_CFG_REG_RESOURCE | ETM4_CFG_RES_CTR) +#define STRB_REG_CTR_RB (STRB_REG_CTR | CS_CFG_REG_VAL_SAVE) +#define STRB_REG_CTR_PRM (STRB_REG_CTR | CS_CFG_REG_VAL_PARAM) +#define STRB_REG_SEQ (CS_CFG_REG_RESOURCE | ETM4_CFG_RES_SEQ) +#define STRB_REG_SEL (CS_CFG_REG_RESOURCE | ETM4_CFG_RES_SEL) +#define STRB_REG_VI (CS_CFG_REG_STD | CS_CFG_REG_VAL_MASK)
This is the 3rd iteration of this set that I review. Along the way I have come to understand most of the things that are presented. The above and all the information packed in .flags is one concept that did not get better as time went by. I have already remarked on the need to split the register address from the flags themselves. I think the remaining flags need further simplification.
Agreed - flags are unclear - so from patch 1 the struct calls out the usage of the values explicitly.
Either some options are removed or a different way to present the information is required. Otherwise I fear people will not be able to write their own preconfigurations.
I think that the change of reg flags to a struct that calls out the useage, plus better docs should address this,.
+static struct cscfg_parameter_desc strobe_params[] = {
{
.name = "window",
.value = 5000,
},
{
.name = "period",
.value = 10000,
},
+};
+static struct cscfg_regval strobe_regs[] = {
/* resource selectors */
{
.flags = STRB_REG_SEL | TRCRSCTLRn(2),
.val32 = 0x20001,
},
{
.flags = STRB_REG_SEQ | TRCRSCTLRn(3),
.val32 = 0x20002,
},
/* strobe window counter 0 - reload from param 0 */
{
.flags = STRB_REG_CTR_RB | TRCCNTVRn(0),
},
{
.flags = STRB_REG_CTR_PRM | TRCCNTRLDVRn(0),
.val32 = 0,
},
{
.flags = STRB_REG_CTR | TRCCNTCTLRn(0),
.val32 = 0x10001,
},
/* strobe period counter 1 - reload from param 1 */
{
.flags = STRB_REG_CTR_RB | TRCCNTVRn(1),
},
{
.flags = STRB_REG_CTR_PRM | TRCCNTRLDVRn(1),
.val32 = 1,
},
{
.flags = STRB_REG_CTR | TRCCNTCTLRn(1),
.val32 = 0x8102,
},
/* sequencer */
{
.flags = STRB_REG_SEQ | TRCSEQEVRn(0),
.val32 = 0x0081,
},
{
.flags = STRB_REG_SEQ | TRCSEQEVRn(1),
.val32 = 0x0000,
},
/* view-inst */
{
.flags = STRB_REG_VI | TRCVICTLR,
.val32 = 0x0003,
.mask32 = 0x0003,
},
/* end of regs */
+};
+static struct cscfg_feature_desc strobe = {
.name = "strobing",
.brief = "Generate periodic trace capture windows.\n"
"parameter \'window\': a number of CPU cycles (W)\n"
"parameter \'period\': trace enabled for W cycles every period x W cycles\n",
.match_flags = CS_CFG_MATCH_CLASS_SRC_ETM4,
.nr_params = ARRAY_SIZE(strobe_params),
.params = strobe_params,
.nr_regs = ARRAY_SIZE(strobe_regs),
.regs = strobe_regs,
+};
+static struct cscfg_feature_desc *preload_feats[] = {
&strobe,
0
+};
+/* create an autofdo configuration */
+/* we will provide 9 sets of preset parameter values */ +#define AFDO_NR_PRESETS 9 +/* the total number of parameters in used features */ +#define AFDO_NR_PARAM_SUM ARRAY_SIZE(strobe_params)
+#define AFDO_MATCH_STROBING (CS_CFG_MATCH_INST_ANY | CS_CFG_MATCH_CLASS_SRC_ETM4)
+static struct cscfg_config_feat_ref afdo_refs[] = {
{
.name = "strobing",
.nr_params = ARRAY_SIZE(strobe_params),
.match = {
.match_flags = AFDO_MATCH_STROBING,
},
},
+};
+/*
- set of presets leaves strobing window constant while varying period to allow
- experimentation with mark / space ratios for various workloads
- */
+static u64 afdo_presets[AFDO_NR_PRESETS][AFDO_NR_PARAM_SUM] = {
{ 5000, 2 },
{ 5000, 4 },
{ 5000, 8 },
{ 5000, 16 },
{ 5000, 64 },
{ 5000, 128 },
{ 5000, 512 },
{ 5000, 1024 },
{ 5000, 4096 },
+};
+static struct cscfg_config_desc afdo = {
.name = "autofdo",
.brief = "Setup ETMs with strobing for autofdo\n"
"Supplied presets allow experimentation with mark-space ratio for various loads\n",
.nr_refs = ARRAY_SIZE(afdo_refs),
.refs = afdo_refs,
.nr_presets = AFDO_NR_PRESETS,
.nr_total_params = AFDO_NR_PARAM_SUM,
.presets = &afdo_presets[0][0],
+};
The current layout works if we have a single preconfiguration but doesn't scale as soon as we need to add a new one. I think the above should be in coresight-afdo.c. That way other preconfiguration can be added to preload_cfgs[] without modifying anything else than the array declaration itself.
Preload configs are both an example and a customer requirement driving this set. Future may move towards choice via dynamic loading.
Thanks and Regards
Mile
+static struct cscfg_config_desc *preload_cfgs[] = {
&afdo,
0
+};
+/* preload called with mutex locked */ +int cscfg_preload(void) +{
return cscfg_load_config_sets(preload_cfgs, preload_feats);
+} diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 481d2b7b6b6f..dca84b3f5fca 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -1680,9 +1680,15 @@ static int __init coresight_init(void)
/* initialise the coresight syscfg API */ ret = cscfg_init();
if (ret)
goto exit_perf_close;
/* preload builtin configurations */
ret = cscfg_preload(); if (!ret) return 0;
+exit_perf_close: etm_perf_exit(); exit_bus_unregister: bus_unregister(&coresight_bustype); diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index ecf4aac7d712..e8f352599dd7 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -45,6 +45,7 @@ struct cscfg_csdev_register { /* internal core operations for cscfg */ int __init cscfg_init(void); void __exit cscfg_exit(void); +int cscfg_preload(void);
/* syscfg external API */ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, -- 2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
Adds configfs subsystem and attributes to the configuration manager to enable the listing of loaded configurations and features.
The default values of feature parameters can be accessed and altered from these attributes to affect all installed devices using the feature.
Signed-off-by: Mike Leach mike.leach@linaro.org --- drivers/hwtracing/coresight/Makefile | 2 +- .../hwtracing/coresight/coresight-config.c | 2 + .../hwtracing/coresight/coresight-config.h | 5 +- .../coresight/coresight-syscfg-configfs.c | 418 ++++++++++++++++++ .../coresight/coresight-syscfg-configfs.h | 47 ++ .../hwtracing/coresight/coresight-syscfg.c | 31 ++ .../hwtracing/coresight/coresight-syscfg.h | 4 + 7 files changed, 507 insertions(+), 2 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-syscfg-configfs.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg-configfs.h
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 9de5586cfd1a..4ec226c44f5b 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \ coresight-sysfs.o coresight-syscfg.o coresight-config.o \ - coresight-cfg-preload.o + coresight-cfg-preload.o coresight-syscfg-configfs.o obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-config.c b/drivers/hwtracing/coresight/coresight-config.c index d911e0f083c1..04e7cb4ff769 100644 --- a/drivers/hwtracing/coresight/coresight-config.c +++ b/drivers/hwtracing/coresight/coresight-config.c @@ -111,8 +111,10 @@ static void cscfg_reset_feat(struct cscfg_feature_csdev *feat) * set the default values for all parameters and regs from the * relevant static descriptors. */ + spin_lock(&feat->desc->param_lock); for (i = 0; i < feat->nr_params; i++) feat->params[i].current_value = feat->desc->params[i].value; + spin_unlock(&feat->desc->param_lock);
for (i = 0; i < feat->nr_regs; i++) { reg_desc = &feat->desc->regs[i]; diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 372f29a59688..39fcac011aa0 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -7,6 +7,7 @@ #ifndef _CORESIGHT_CORESIGHT_CONFIG_H #define _CORESIGHT_CORESIGHT_CONFIG_H
+#include <linux/configfs.h> #include <linux/coresight.h> #include <linux/types.h>
@@ -89,6 +90,7 @@ struct cscfg_regval { * @match_flags: matching information if loading into a device * @nr_params: number of parameters used. * @params: array of parameters used. + * @param_lock: protect params when accessing default values. * @nr_regs: number of registers used. * @reg: array of registers used. */ @@ -99,6 +101,7 @@ struct cscfg_feature_desc { u32 match_flags; int nr_params; struct cscfg_parameter_desc *params; + spinlock_t param_lock; int nr_regs; struct cscfg_regval *regs; }; @@ -239,7 +242,7 @@ struct cscfg_feat_ops { * @ops: standard ops to enable and disable features on devices. */ struct cscfg_feature_csdev { - const struct cscfg_feature_desc *desc; + struct cscfg_feature_desc *desc; struct coresight_device *csdev; struct list_head node; spinlock_t *csdev_spinlock; diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c new file mode 100644 index 000000000000..ff7ea678100a --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c @@ -0,0 +1,418 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Linaro Limited, All rights reserved. + * Author: Mike Leach mike.leach@linaro.org + */ + +#include <linux/configfs.h> + +#include "coresight-syscfg-configfs.h" + +/* + * configfs support for syscfg device. + * + * config fs is used to manage configurations and features on the + * coresight system. + */ + +static struct cscfg_device *cscfg_fs_get_cscfg_dev(void); + +static struct device *cscfg_dev_to_dev(void) +{ + return cscfg_fs_get_cscfg_dev() ? &cscfg_fs_get_cscfg_dev()->dev : NULL; +} + +/* + * Declare the subsystem - with base attributes allowing listing of + * loaded configurations + */ +static inline struct cscfg_fs_config *to_cscfg_fs_config_group(struct config_group *group) +{ + return container_of(group, struct cscfg_fs_config, group); +} + +/* configurations sub-group */ + +/* attributes for the config view group */ +static ssize_t cscfg_cfg_description_show(struct config_item *item, char *page) +{ + struct cscfg_fs_config *fs_config = to_cscfg_fs_config_group(to_config_group(item)); + + return scnprintf(page, PAGE_SIZE, "%s\n", fs_config->desc->brief); +} +CONFIGFS_ATTR_RO(cscfg_cfg_, description); + +static ssize_t cscfg_cfg_refs_show(struct config_item *item, char *page) +{ + struct cscfg_fs_config *fs_config = to_cscfg_fs_config_group(to_config_group(item)); + const struct cscfg_config_desc *desc = fs_config->desc; + ssize_t ch_used = 0; + int i; + + if (desc->nr_refs) { + ch_used += scnprintf(page, PAGE_SIZE, "references %d features:-\n", desc->nr_refs); + for (i = 0; i < desc->nr_refs; i++) { + ch_used += scnprintf(page + ch_used, PAGE_SIZE - ch_used, + "%s\n", desc->refs[i].name); + } + } else + ch_used = scnprintf(page, PAGE_SIZE, "no features referenced\n"); + return ch_used; +} +CONFIGFS_ATTR_RO(cscfg_cfg_, refs); + +static ssize_t cscfg_cfg_nr_presets_show(struct config_item *item, char *page) +{ + struct cscfg_fs_config *fs_config = to_cscfg_fs_config_group(to_config_group(item)); + + return scnprintf(page, PAGE_SIZE, "%d\n", fs_config->desc->nr_presets); +} +CONFIGFS_ATTR_RO(cscfg_cfg_, nr_presets); + +static ssize_t cscfg_cfg_preset_values_show(struct config_item *item, char *page) +{ + struct cscfg_fs_config *fs_config = to_cscfg_fs_config_group(to_config_group(item)); + const struct cscfg_config_desc *cfg = fs_config->desc; + const struct cscfg_feature_desc *feat; + ssize_t used = 0; + int i, j, val_idx, preset_idx; + + if (!fs_config->desc->nr_presets) + return scnprintf(page, PAGE_SIZE, "No presets defined\n"); + + used = scnprintf(page, PAGE_SIZE, "%d presets, %d parameters per preset\n", + fs_config->desc->nr_presets, cfg->nr_total_params); + + for (preset_idx = 0; preset_idx < fs_config->desc->nr_presets; preset_idx++) { + /* start index on the correct array line */ + val_idx = cfg->nr_total_params * preset_idx; + + /* preset indexes are used as 1 based by the user */ + used += scnprintf(page + used, PAGE_SIZE - used, "preset[%d]: ", preset_idx+1); + + /* + * A set of presets is the sum of all params in used features, + * in order of declaration of features and params in the features + */ + for (i = 0; i < cfg->nr_refs; i++) { + feat = cscfg_get_named_feat_desc(cfg->refs[i].name); + for (j = 0; j < cfg->refs[i].nr_params; j++) { + used += scnprintf(page + used, PAGE_SIZE - used, + "%s.%s = 0x%llx ", + cfg->refs[i].name, feat->params[j].name, + cfg->presets[val_idx++]); + } + } + used += scnprintf(page + used, PAGE_SIZE - used, "\n"); + } + return used; +} +CONFIGFS_ATTR_RO(cscfg_cfg_, preset_values); + +static struct configfs_attribute *cscfg_config_view_attrs[] = { + &cscfg_cfg_attr_description, + &cscfg_cfg_attr_refs, + &cscfg_cfg_attr_nr_presets, + &cscfg_cfg_attr_preset_values, + NULL, +}; + +static struct config_item_type cscfg_config_view_type = { + .ct_owner = THIS_MODULE, + .ct_attrs = cscfg_config_view_attrs, +}; + +static struct config_group *cscfg_create_config_group(struct cscfg_config_desc *cfg_desc) +{ + struct cscfg_fs_config *cfg_view; + struct device *dev = cscfg_dev_to_dev(); + + if (!dev) + return ERR_PTR(-EINVAL); + + cfg_view = devm_kzalloc(dev, sizeof(struct cscfg_fs_config), GFP_KERNEL); + if (!cfg_view) + return ERR_PTR(-ENOMEM); + + cfg_view->desc = cfg_desc; + config_group_init_type_name(&cfg_view->group, cfg_desc->name, &cscfg_config_view_type); + return &cfg_view->group; +} + +static struct config_item_type cscfg_configs_type = { + .ct_owner = THIS_MODULE, +}; + +static struct cscfg_fs_def_group cscfg_configs_grp = { + .group = { + .cg_item = { + .ci_namebuf = "configurations", + .ci_type = &cscfg_configs_type, + }, + }, +}; + + +/* attributes for features view */ + +static inline struct cscfg_fs_feature *to_cscfg_fs_feature_group(struct config_group *group) +{ + return container_of(group, struct cscfg_fs_feature, group); +} + +static ssize_t cscfg_feat_description_show(struct config_item *item, char *page) +{ + struct cscfg_fs_feature *fs_feat = to_cscfg_fs_feature_group(to_config_group(item)); + + return scnprintf(page, PAGE_SIZE, "%s\n", fs_feat->desc->brief); +} +CONFIGFS_ATTR_RO(cscfg_feat_, description); + +static ssize_t cscfg_feat_matches_show(struct config_item *item, char *page) +{ + struct cscfg_fs_feature *fs_feat = to_cscfg_fs_feature_group(to_config_group(item)); + u32 match_flags = fs_feat->desc->match_flags; + int used = 0; + + if (match_flags & CS_CFG_MATCH_CLASS_SRC_ALL) + used = scnprintf(page, PAGE_SIZE, "SRC_ALL "); + + if (match_flags & CS_CFG_MATCH_CLASS_SRC_ETM4) + used += scnprintf(page + used, PAGE_SIZE - used, "SRC_ETMV4 "); + + if (match_flags & CS_CFG_MATCH_CLASS_CTI_ALL) + used += scnprintf(page + used, PAGE_SIZE - used, "CTI_ALL "); + + if (match_flags & CS_CFG_MATCH_CLASS_CTI_CPU) + used += scnprintf(page + used, PAGE_SIZE - used, "CTI_CPU "); + + if (match_flags & CS_CFG_MATCH_CLASS_CTI_SYS) + used += scnprintf(page + used, PAGE_SIZE - used, "CTI_SYS "); + + used += scnprintf(page + used, PAGE_SIZE - used, "\n"); + return used; +} +CONFIGFS_ATTR_RO(cscfg_feat_, matches); + +static ssize_t cscfg_feat_nr_params_show(struct config_item *item, char *page) +{ + struct cscfg_fs_feature *fs_feat = to_cscfg_fs_feature_group(to_config_group(item)); + + return scnprintf(page, PAGE_SIZE, "%d\n", fs_feat->desc->nr_params); +} +CONFIGFS_ATTR_RO(cscfg_feat_, nr_params); + +/* base feature desc attrib structures */ +static struct configfs_attribute *cscfg_feature_view_attrs[] = { + &cscfg_feat_attr_description, + &cscfg_feat_attr_matches, + &cscfg_feat_attr_nr_params, + NULL, +}; + +static struct config_item_type cscfg_feature_view_type = { + .ct_owner = THIS_MODULE, + .ct_attrs = cscfg_feature_view_attrs, +}; + +static inline struct cscfg_fs_param *to_cscfg_fs_param_group(struct config_group *group) +{ + return container_of(group, struct cscfg_fs_param, group); +} + +static ssize_t cscfg_param_value_show(struct config_item *item, char *page) +{ + struct cscfg_fs_param *param_item = to_cscfg_fs_param_group(to_config_group(item)); + + return scnprintf(page, PAGE_SIZE, "0x%llx\n", param_item->param->value); +} + +static ssize_t cscfg_param_value_store(struct config_item *item, + const char *page, size_t size) +{ + struct cscfg_fs_param *param_item = to_cscfg_fs_param_group(to_config_group(item)); + u64 val; + int err; + + err = kstrtoull(page, 0, &val); + if (err) + return err; + + spin_lock(¶m_item->desc->param_lock); + param_item->param->value = val; + spin_unlock(¶m_item->desc->param_lock); + + return size; +} +CONFIGFS_ATTR(cscfg_param_, value); + +static struct configfs_attribute *cscfg_param_view_attrs[] = { + &cscfg_param_attr_value, + NULL, +}; + +static struct config_item_type cscfg_param_view_type = { + .ct_owner = THIS_MODULE, + .ct_attrs = cscfg_param_view_attrs, +}; + +static struct config_item_type cscfg_feat_param_group_type = { + .ct_owner = THIS_MODULE, +}; + +/* + * configfs has far less functionality provided to add attributes dynamically than sysfs, + * and the show and store fns pass the enclosing config_item so the actual attribute cannot + * be determined. Therefore we add each item as a group directory, with a value attribute. + */ +static int cscfg_create_params_group_items(struct cscfg_feature_desc *feat_desc, + struct config_group *params_group) +{ + struct device *dev = cscfg_dev_to_dev(); + struct cscfg_fs_param *param_item; + int i; + + /* parameter items - as groups with default_value attribute */ + for (i = 0; i < feat_desc->nr_params; i++) { + param_item = devm_kzalloc(dev, sizeof(struct cscfg_fs_param), GFP_KERNEL); + if (!param_item) + return -ENOMEM; + param_item->desc = feat_desc; + param_item->param = &feat_desc->params[i]; + config_group_init_type_name(¶m_item->group, param_item->param->name, + &cscfg_param_view_type); + configfs_add_default_group(¶m_item->group, params_group); + } + return 0; +} + +static struct config_group *cscfg_create_feature_group(struct cscfg_feature_desc *feat_desc) +{ + struct cscfg_fs_feature *feat_view; + struct device *dev = cscfg_dev_to_dev(); + struct cscfg_fs_def_group *params_group = NULL; + int item_err; + + if (!dev) + return ERR_PTR(-EINVAL); + + feat_view = devm_kzalloc(dev, sizeof(struct cscfg_fs_feature), GFP_KERNEL); + if (!feat_view) + return ERR_PTR(-ENOMEM); + + if (feat_desc->nr_params) { + params_group = devm_kzalloc(dev, sizeof(struct cscfg_fs_feature), GFP_KERNEL); + if (!params_group) + return ERR_PTR(-ENOMEM); + } + + feat_view->desc = feat_desc; + config_group_init_type_name(&feat_view->group, + feat_desc->name, + &cscfg_feature_view_type); + if (params_group) { + config_group_init_type_name(¶ms_group->group, "params", + &cscfg_feat_param_group_type); + configfs_add_default_group(¶ms_group->group, &feat_view->group); + item_err = cscfg_create_params_group_items(feat_desc, ¶ms_group->group); + if (item_err) + return ERR_PTR(item_err); + } + return &feat_view->group; +} + +static struct config_item_type cscfg_features_type = { + .ct_owner = THIS_MODULE, +}; + +static struct cscfg_fs_def_group cscfg_features_grp = { + .group = { + .cg_item = { + .ci_namebuf = "features", + .ci_type = &cscfg_features_type, + }, + }, +}; + +/* add configuration to configurations group */ +int cscfg_configfs_add_config(struct cscfg_config_desc *cfg_desc) +{ + struct config_group *new_group; + int err; + + new_group = cscfg_create_config_group(cfg_desc); + if (IS_ERR(new_group)) + return PTR_ERR(new_group); + err = configfs_register_group(&cscfg_configs_grp.group, new_group); + return err; +} + +/* add feature to features group */ +int cscfg_configfs_add_feature(struct cscfg_feature_desc *feat_desc) +{ + struct config_group *new_group; + int err; + + new_group = cscfg_create_feature_group(feat_desc); + if (IS_ERR(new_group)) + return PTR_ERR(new_group); + err = configfs_register_group(&cscfg_features_grp.group, new_group); + return err; +} + +static const struct config_item_type syscfg_fs_type = { + .ct_owner = THIS_MODULE, +}; + +static struct cscfg_fs_subsys syscfg_fs_subsys = { + .cfgdev = NULL, + .fs_subsys = { + .su_group = { + .cg_item = { + .ci_namebuf = "coresight-syscfg", + .ci_type = &syscfg_fs_type, + }, + }, + }, +}; + +static inline struct cscfg_device *cscfg_fs_get_cscfg_dev(void) +{ + return syscfg_fs_subsys.cfgdev; +} + +int cscfg_configfs_init(struct cscfg_device *cscfg_dev) +{ + int ret = 0; + struct configfs_subsystem *subsys = &syscfg_fs_subsys.fs_subsys; + + if (!cscfg_dev) + return -EINVAL; + + config_group_init(&subsys->su_group); + mutex_init(&subsys->su_mutex); + + /* Add default groups to subsystem */ + config_group_init(&cscfg_configs_grp.group); + configfs_add_default_group(&cscfg_configs_grp.group, &subsys->su_group); + + config_group_init(&cscfg_features_grp.group); + configfs_add_default_group(&cscfg_features_grp.group, &subsys->su_group); + + ret = configfs_register_subsystem(subsys); + if (!ret) { + syscfg_fs_subsys.cfgdev = cscfg_dev; + cscfg_dev->cfgfs_subsys = &syscfg_fs_subsys; + } + + return ret; +} + +void cscfg_configfs_release(struct cscfg_device *cscfg_dev) +{ + if (cscfg_dev && cscfg_dev->cfgfs_subsys) { + configfs_unregister_subsystem(&cscfg_dev->cfgfs_subsys->fs_subsys); + cscfg_dev->cfgfs_subsys = NULL; + } + syscfg_fs_subsys.cfgdev = NULL; +} diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.h b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h new file mode 100644 index 000000000000..70cc3745649e --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Coresight system configuration driver - support for configfs. + */ + +#ifndef CORESIGHT_SYSCFG_CONFIGFS_H +#define CORESIGHT_SYSCFG_CONFIGFS_H + +#include <linux/configfs.h> +#include "coresight-syscfg.h" + +/* container to associate the device and configfs subsystem */ +struct cscfg_fs_subsys { + struct cscfg_device *cfgdev; + struct configfs_subsystem fs_subsys; +}; + +/* container for default groups */ +struct cscfg_fs_def_group { + struct config_group group; +}; + +/* container for configuration view */ +struct cscfg_fs_config { + struct cscfg_config_desc *desc; + struct config_group group; +}; + +/* container for feature view */ +struct cscfg_fs_feature { + struct cscfg_feature_desc *desc; + struct config_group group; +}; + +/* container for parameter view */ +struct cscfg_fs_param { + struct cscfg_parameter_desc *param; + struct cscfg_feature_desc *desc; + struct config_group group; +}; + +int cscfg_configfs_init(struct cscfg_device *dev); +void cscfg_configfs_release(struct cscfg_device *dev); +int cscfg_configfs_add_config(struct cscfg_config_desc *cfg_desc); +int cscfg_configfs_add_feature(struct cscfg_feature_desc *feat_desc); + +#endif /* CORESIGHT_SYSCFG_CONFIGFS_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 8d52580daf04..2cf67a038cc8 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -9,6 +9,7 @@ #include "coresight-config.h" #include "coresight-etm-perf.h" #include "coresight-syscfg.h" +#include "coresight-syscfg-configfs.h"
/* * cscfg_ API manages configurations and features for the entire coresight @@ -260,6 +261,8 @@ static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc) { int err;
+ spin_lock_init(&feat_desc->param_lock); + /* add feature to any matching registered devices */ err = cscfg_add_feat_to_csdevs(feat_desc); if (err) @@ -294,6 +297,24 @@ static int cscfg_load_config(struct cscfg_config_desc *cfg_desc) return err; }
+/* get a feature descriptor by name */ +const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name) +{ + const struct cscfg_feature_desc *feat = NULL, *feat_item; + + mutex_lock(&cscfg_mutex); + + list_for_each_entry(feat_item, &cscfg_data.feat_list, item) { + if (strcmp(feat_item->name, name) == 0) { + feat = feat_item; + break; + } + } + + mutex_unlock(&cscfg_mutex); + return feat; +} + /* * External API function to load feature and config sets. * Take a 0 terminated array of feature descriptors and/or configuration @@ -316,6 +337,7 @@ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, feat_descs[i]->name); goto do_unlock; } + cscfg_configfs_add_feature(feat_descs[i]); i++; } } @@ -330,6 +352,7 @@ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, cfg_descs[i]->name); goto do_unlock; } + cscfg_configfs_add_config(cfg_descs[i]); i++; } } @@ -502,6 +525,7 @@ struct device *to_device_cscfg(void) /* Must have a release function or the kernel will complain on module unload */ void cscfg_dev_release(struct device *dev) { + cscfg_configfs_release(cscfg_dev); kfree(cscfg_dev); cscfg_dev = NULL; } @@ -530,6 +554,7 @@ int cscfg_create_device(void) cscfg_dev->cfg_data = &cscfg_data;
err = device_register(dev); + if (err) cscfg_dev_release(dev);
@@ -587,6 +612,10 @@ int __init cscfg_init(void) if (err) goto exit_drv_unregister;
+ err = cscfg_configfs_init(cscfg_dev); + if (err) + goto exit_dev_clear; + INIT_LIST_HEAD(&cscfg_data.dev_list); INIT_LIST_HEAD(&cscfg_data.feat_list); INIT_LIST_HEAD(&cscfg_data.config_list); @@ -595,6 +624,8 @@ int __init cscfg_init(void) dev_info(to_device_cscfg(), "CoreSight Configuration manager initialised"); return 0;
+exit_dev_clear: + cscfg_clear_device(); exit_drv_unregister: cscfg_driver_exit(); exit_bus_unregister: diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index e8f352599dd7..ce237a69677b 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -6,6 +6,7 @@ #ifndef CORESIGHT_SYSCFG_H #define CORESIGHT_SYSCFG_H
+#include <linux/configfs.h> #include <linux/coresight.h> #include <linux/device.h>
@@ -46,6 +47,7 @@ struct cscfg_csdev_register { int __init cscfg_init(void); void __exit cscfg_exit(void); int cscfg_preload(void); +const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name);
/* syscfg external API */ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, @@ -64,10 +66,12 @@ void cscfg_unregister_csdev(struct coresight_device *csdev); * * @dev: The device. * @cfg_data: A reference to the configuration and feature lists + * @cfgfs_subsys: configfs subsystem used to manage configurations. */ struct cscfg_device { struct device dev; struct cscfg_api_data *cfg_data; + struct cscfg_fs_subsys *cfgfs_subsys; };
/* basic device driver */
On Fri, Oct 30, 2020 at 05:56:53PM +0000, Mike Leach wrote:
Adds configfs subsystem and attributes to the configuration manager to enable the listing of loaded configurations and features.
The default values of feature parameters can be accessed and altered from these attributes to affect all installed devices using the feature.
Please no dot (.) at the end of the title. The same goes for 9/9.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 2 +- .../hwtracing/coresight/coresight-config.c | 2 + .../hwtracing/coresight/coresight-config.h | 5 +- .../coresight/coresight-syscfg-configfs.c | 418 ++++++++++++++++++ .../coresight/coresight-syscfg-configfs.h | 47 ++ .../hwtracing/coresight/coresight-syscfg.c | 31 ++ .../hwtracing/coresight/coresight-syscfg.h | 4 + 7 files changed, 507 insertions(+), 2 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-syscfg-configfs.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg-configfs.h
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 9de5586cfd1a..4ec226c44f5b 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \ coresight-sysfs.o coresight-syscfg.o coresight-config.o \
coresight-cfg-preload.o
coresight-cfg-preload.o coresight-syscfg-configfs.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-config.c b/drivers/hwtracing/coresight/coresight-config.c index d911e0f083c1..04e7cb4ff769 100644 --- a/drivers/hwtracing/coresight/coresight-config.c +++ b/drivers/hwtracing/coresight/coresight-config.c @@ -111,8 +111,10 @@ static void cscfg_reset_feat(struct cscfg_feature_csdev *feat) * set the default values for all parameters and regs from the * relevant static descriptors. */
- spin_lock(&feat->desc->param_lock); for (i = 0; i < feat->nr_params; i++) feat->params[i].current_value = feat->desc->params[i].value;
- spin_unlock(&feat->desc->param_lock);
for (i = 0; i < feat->nr_regs; i++) { reg_desc = &feat->desc->regs[i]; diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 372f29a59688..39fcac011aa0 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -7,6 +7,7 @@ #ifndef _CORESIGHT_CORESIGHT_CONFIG_H #define _CORESIGHT_CORESIGHT_CONFIG_H +#include <linux/configfs.h>
I don't see a need for that header file.
#include <linux/coresight.h> #include <linux/types.h> @@ -89,6 +90,7 @@ struct cscfg_regval {
- @match_flags: matching information if loading into a device
- @nr_params: number of parameters used.
- @params: array of parameters used.
*/
- @param_lock: protect params when accessing default values.
- @nr_regs: number of registers used.
- @reg: array of registers used.
@@ -99,6 +101,7 @@ struct cscfg_feature_desc { u32 match_flags; int nr_params; struct cscfg_parameter_desc *params;
- spinlock_t param_lock;
I'll skip over this for now but all these locks are increasing the potential of making the lockdep mechanic very angry, if it hasn't already done so.
int nr_regs; struct cscfg_regval *regs; }; @@ -239,7 +242,7 @@ struct cscfg_feat_ops {
- @ops: standard ops to enable and disable features on devices.
*/ struct cscfg_feature_csdev {
- const struct cscfg_feature_desc *desc;
- struct cscfg_feature_desc *desc;
Please don't change what has aleady been added. Simply skip the 'const' when you first introduce the structure.
struct coresight_device *csdev; struct list_head node; spinlock_t *csdev_spinlock; diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c new file mode 100644 index 000000000000..ff7ea678100a --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c @@ -0,0 +1,418 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <linux/configfs.h>
+#include "coresight-syscfg-configfs.h"
+/*
- configfs support for syscfg device.
- config fs is used to manage configurations and features on the
- coresight system.
- */
+static struct cscfg_device *cscfg_fs_get_cscfg_dev(void);
+static struct device *cscfg_dev_to_dev(void) +{
- return cscfg_fs_get_cscfg_dev() ? &cscfg_fs_get_cscfg_dev()->dev : NULL;
+}
+/*
- Declare the subsystem - with base attributes allowing listing of
- loaded configurations
- */
+static inline struct cscfg_fs_config *to_cscfg_fs_config_group(struct config_group *group) +{
- return container_of(group, struct cscfg_fs_config, group);
+}
+/* configurations sub-group */
+/* attributes for the config view group */ +static ssize_t cscfg_cfg_description_show(struct config_item *item, char *page) +{
- struct cscfg_fs_config *fs_config = to_cscfg_fs_config_group(to_config_group(item));
- return scnprintf(page, PAGE_SIZE, "%s\n", fs_config->desc->brief);
+} +CONFIGFS_ATTR_RO(cscfg_cfg_, description);
+static ssize_t cscfg_cfg_refs_show(struct config_item *item, char *page) +{
- struct cscfg_fs_config *fs_config = to_cscfg_fs_config_group(to_config_group(item));
- const struct cscfg_config_desc *desc = fs_config->desc;
- ssize_t ch_used = 0;
- int i;
- if (desc->nr_refs) {
ch_used += scnprintf(page, PAGE_SIZE, "references %d features:-\n", desc->nr_refs);
for (i = 0; i < desc->nr_refs; i++) {
ch_used += scnprintf(page + ch_used, PAGE_SIZE - ch_used,
"%s\n", desc->refs[i].name);
}
- } else
ch_used = scnprintf(page, PAGE_SIZE, "no features referenced\n");
- return ch_used;
+} +CONFIGFS_ATTR_RO(cscfg_cfg_, refs);
+static ssize_t cscfg_cfg_nr_presets_show(struct config_item *item, char *page) +{
- struct cscfg_fs_config *fs_config = to_cscfg_fs_config_group(to_config_group(item));
- return scnprintf(page, PAGE_SIZE, "%d\n", fs_config->desc->nr_presets);
+} +CONFIGFS_ATTR_RO(cscfg_cfg_, nr_presets);
+static ssize_t cscfg_cfg_preset_values_show(struct config_item *item, char *page) +{
- struct cscfg_fs_config *fs_config = to_cscfg_fs_config_group(to_config_group(item));
- const struct cscfg_config_desc *cfg = fs_config->desc;
- const struct cscfg_feature_desc *feat;
- ssize_t used = 0;
- int i, j, val_idx, preset_idx;
- if (!fs_config->desc->nr_presets)
return scnprintf(page, PAGE_SIZE, "No presets defined\n");
- used = scnprintf(page, PAGE_SIZE, "%d presets, %d parameters per preset\n",
fs_config->desc->nr_presets, cfg->nr_total_params);
- for (preset_idx = 0; preset_idx < fs_config->desc->nr_presets; preset_idx++) {
/* start index on the correct array line */
val_idx = cfg->nr_total_params * preset_idx;
/* preset indexes are used as 1 based by the user */
used += scnprintf(page + used, PAGE_SIZE - used, "preset[%d]: ", preset_idx+1);
/*
* A set of presets is the sum of all params in used features,
* in order of declaration of features and params in the features
*/
for (i = 0; i < cfg->nr_refs; i++) {
feat = cscfg_get_named_feat_desc(cfg->refs[i].name);
for (j = 0; j < cfg->refs[i].nr_params; j++) {
used += scnprintf(page + used, PAGE_SIZE - used,
"%s.%s = 0x%llx ",
cfg->refs[i].name, feat->params[j].name,
cfg->presets[val_idx++]);
}
}
used += scnprintf(page + used, PAGE_SIZE - used, "\n");
- }
- return used;
+} +CONFIGFS_ATTR_RO(cscfg_cfg_, preset_values);
+static struct configfs_attribute *cscfg_config_view_attrs[] = {
- &cscfg_cfg_attr_description,
- &cscfg_cfg_attr_refs,
- &cscfg_cfg_attr_nr_presets,
- &cscfg_cfg_attr_preset_values,
- NULL,
+};
+static struct config_item_type cscfg_config_view_type = {
- .ct_owner = THIS_MODULE,
- .ct_attrs = cscfg_config_view_attrs,
+};
+static struct config_group *cscfg_create_config_group(struct cscfg_config_desc *cfg_desc) +{
- struct cscfg_fs_config *cfg_view;
- struct device *dev = cscfg_dev_to_dev();
- if (!dev)
return ERR_PTR(-EINVAL);
- cfg_view = devm_kzalloc(dev, sizeof(struct cscfg_fs_config), GFP_KERNEL);
- if (!cfg_view)
return ERR_PTR(-ENOMEM);
- cfg_view->desc = cfg_desc;
- config_group_init_type_name(&cfg_view->group, cfg_desc->name, &cscfg_config_view_type);
- return &cfg_view->group;
+}
+static struct config_item_type cscfg_configs_type = {
- .ct_owner = THIS_MODULE,
+};
+static struct cscfg_fs_def_group cscfg_configs_grp = {
- .group = {
.cg_item = {
.ci_namebuf = "configurations",
.ci_type = &cscfg_configs_type,
},
- },
+};
Extra line
+/* attributes for features view */
+static inline struct cscfg_fs_feature *to_cscfg_fs_feature_group(struct config_group *group) +{
- return container_of(group, struct cscfg_fs_feature, group);
+}
+static ssize_t cscfg_feat_description_show(struct config_item *item, char *page) +{
- struct cscfg_fs_feature *fs_feat = to_cscfg_fs_feature_group(to_config_group(item));
- return scnprintf(page, PAGE_SIZE, "%s\n", fs_feat->desc->brief);
+} +CONFIGFS_ATTR_RO(cscfg_feat_, description);
+static ssize_t cscfg_feat_matches_show(struct config_item *item, char *page) +{
- struct cscfg_fs_feature *fs_feat = to_cscfg_fs_feature_group(to_config_group(item));
- u32 match_flags = fs_feat->desc->match_flags;
- int used = 0;
- if (match_flags & CS_CFG_MATCH_CLASS_SRC_ALL)
used = scnprintf(page, PAGE_SIZE, "SRC_ALL ");
- if (match_flags & CS_CFG_MATCH_CLASS_SRC_ETM4)
used += scnprintf(page + used, PAGE_SIZE - used, "SRC_ETMV4 ");
- if (match_flags & CS_CFG_MATCH_CLASS_CTI_ALL)
used += scnprintf(page + used, PAGE_SIZE - used, "CTI_ALL ");
- if (match_flags & CS_CFG_MATCH_CLASS_CTI_CPU)
used += scnprintf(page + used, PAGE_SIZE - used, "CTI_CPU ");
- if (match_flags & CS_CFG_MATCH_CLASS_CTI_SYS)
used += scnprintf(page + used, PAGE_SIZE - used, "CTI_SYS ");
- used += scnprintf(page + used, PAGE_SIZE - used, "\n");
- return used;
+} +CONFIGFS_ATTR_RO(cscfg_feat_, matches);
+static ssize_t cscfg_feat_nr_params_show(struct config_item *item, char *page) +{
- struct cscfg_fs_feature *fs_feat = to_cscfg_fs_feature_group(to_config_group(item));
- return scnprintf(page, PAGE_SIZE, "%d\n", fs_feat->desc->nr_params);
+} +CONFIGFS_ATTR_RO(cscfg_feat_, nr_params);
+/* base feature desc attrib structures */ +static struct configfs_attribute *cscfg_feature_view_attrs[] = {
- &cscfg_feat_attr_description,
- &cscfg_feat_attr_matches,
- &cscfg_feat_attr_nr_params,
- NULL,
+};
+static struct config_item_type cscfg_feature_view_type = {
- .ct_owner = THIS_MODULE,
- .ct_attrs = cscfg_feature_view_attrs,
+};
+static inline struct cscfg_fs_param *to_cscfg_fs_param_group(struct config_group *group) +{
- return container_of(group, struct cscfg_fs_param, group);
+}
+static ssize_t cscfg_param_value_show(struct config_item *item, char *page) +{
- struct cscfg_fs_param *param_item = to_cscfg_fs_param_group(to_config_group(item));
- return scnprintf(page, PAGE_SIZE, "0x%llx\n", param_item->param->value);
+}
+static ssize_t cscfg_param_value_store(struct config_item *item,
const char *page, size_t size)
+{
- struct cscfg_fs_param *param_item = to_cscfg_fs_param_group(to_config_group(item));
- u64 val;
- int err;
- err = kstrtoull(page, 0, &val);
- if (err)
return err;
- spin_lock(¶m_item->desc->param_lock);
- param_item->param->value = val;
- spin_unlock(¶m_item->desc->param_lock);
- return size;
+} +CONFIGFS_ATTR(cscfg_param_, value);
+static struct configfs_attribute *cscfg_param_view_attrs[] = {
- &cscfg_param_attr_value,
- NULL,
+};
+static struct config_item_type cscfg_param_view_type = {
- .ct_owner = THIS_MODULE,
- .ct_attrs = cscfg_param_view_attrs,
+};
+static struct config_item_type cscfg_feat_param_group_type = {
- .ct_owner = THIS_MODULE,
+};
+/*
- configfs has far less functionality provided to add attributes dynamically than sysfs,
- and the show and store fns pass the enclosing config_item so the actual attribute cannot
- be determined. Therefore we add each item as a group directory, with a value attribute.
- */
+static int cscfg_create_params_group_items(struct cscfg_feature_desc *feat_desc,
struct config_group *params_group)
+{
- struct device *dev = cscfg_dev_to_dev();
- struct cscfg_fs_param *param_item;
- int i;
- /* parameter items - as groups with default_value attribute */
- for (i = 0; i < feat_desc->nr_params; i++) {
param_item = devm_kzalloc(dev, sizeof(struct cscfg_fs_param), GFP_KERNEL);
if (!param_item)
return -ENOMEM;
param_item->desc = feat_desc;
param_item->param = &feat_desc->params[i];
config_group_init_type_name(¶m_item->group, param_item->param->name,
&cscfg_param_view_type);
configfs_add_default_group(¶m_item->group, params_group);
- }
- return 0;
+}
+static struct config_group *cscfg_create_feature_group(struct cscfg_feature_desc *feat_desc) +{
- struct cscfg_fs_feature *feat_view;
- struct device *dev = cscfg_dev_to_dev();
- struct cscfg_fs_def_group *params_group = NULL;
- int item_err;
- if (!dev)
return ERR_PTR(-EINVAL);
- feat_view = devm_kzalloc(dev, sizeof(struct cscfg_fs_feature), GFP_KERNEL);
- if (!feat_view)
return ERR_PTR(-ENOMEM);
- if (feat_desc->nr_params) {
params_group = devm_kzalloc(dev, sizeof(struct cscfg_fs_feature), GFP_KERNEL);
if (!params_group)
return ERR_PTR(-ENOMEM);
- }
- feat_view->desc = feat_desc;
- config_group_init_type_name(&feat_view->group,
feat_desc->name,
&cscfg_feature_view_type);
- if (params_group) {
config_group_init_type_name(¶ms_group->group, "params",
&cscfg_feat_param_group_type);
configfs_add_default_group(¶ms_group->group, &feat_view->group);
item_err = cscfg_create_params_group_items(feat_desc, ¶ms_group->group);
if (item_err)
return ERR_PTR(item_err);
- }
- return &feat_view->group;
+}
+static struct config_item_type cscfg_features_type = {
- .ct_owner = THIS_MODULE,
+};
+static struct cscfg_fs_def_group cscfg_features_grp = {
- .group = {
.cg_item = {
.ci_namebuf = "features",
.ci_type = &cscfg_features_type,
},
- },
Can we do the following to avoid declaring cscfg_features_type:
static struct cscfg_fs_def_group cscfg_features_grp = { .group = { .cg_item = { .ci_namebuf = "features", .ci_type = { .ct_owner = THIS_MODULE, }; }, },
Same for configuration.
+};
+/* add configuration to configurations group */ +int cscfg_configfs_add_config(struct cscfg_config_desc *cfg_desc) +{
- struct config_group *new_group;
- int err;
- new_group = cscfg_create_config_group(cfg_desc);
- if (IS_ERR(new_group))
return PTR_ERR(new_group);
- err = configfs_register_group(&cscfg_configs_grp.group, new_group);
- return err;
+}
+/* add feature to features group */ +int cscfg_configfs_add_feature(struct cscfg_feature_desc *feat_desc) +{
- struct config_group *new_group;
- int err;
- new_group = cscfg_create_feature_group(feat_desc);
- if (IS_ERR(new_group))
return PTR_ERR(new_group);
- err = configfs_register_group(&cscfg_features_grp.group, new_group);
- return err;
+}
+static const struct config_item_type syscfg_fs_type = {
- .ct_owner = THIS_MODULE,
+};
+static struct cscfg_fs_subsys syscfg_fs_subsys = {
- .cfgdev = NULL,
- .fs_subsys = {
.su_group = {
.cg_item = {
.ci_namebuf = "coresight-syscfg",
.ci_type = &syscfg_fs_type,
},
},
- },
+};
+static inline struct cscfg_device *cscfg_fs_get_cscfg_dev(void) +{
- return syscfg_fs_subsys.cfgdev;
+}
+int cscfg_configfs_init(struct cscfg_device *cscfg_dev) +{
- int ret = 0;
- struct configfs_subsystem *subsys = &syscfg_fs_subsys.fs_subsys;
- if (!cscfg_dev)
return -EINVAL;
- config_group_init(&subsys->su_group);
- mutex_init(&subsys->su_mutex);
- /* Add default groups to subsystem */
- config_group_init(&cscfg_configs_grp.group);
- configfs_add_default_group(&cscfg_configs_grp.group, &subsys->su_group);
- config_group_init(&cscfg_features_grp.group);
- configfs_add_default_group(&cscfg_features_grp.group, &subsys->su_group);
- ret = configfs_register_subsystem(subsys);
- if (!ret) {
syscfg_fs_subsys.cfgdev = cscfg_dev;
cscfg_dev->cfgfs_subsys = &syscfg_fs_subsys;
- }
Instead of doing the above I suggest to make cscfg_device::cfgfs_subsys a member rather than a pointer and call containerof() to get back to the cscfg_device. That way we avoid the static declaration of cscfg_configs_grp and cscfg_configs_type above.
Moreover, now that this patchset is sinking in I would rename struct cscfg_device to cscfg_manager.
- return ret;
+}
+void cscfg_configfs_release(struct cscfg_device *cscfg_dev) +{
- if (cscfg_dev && cscfg_dev->cfgfs_subsys) {
configfs_unregister_subsystem(&cscfg_dev->cfgfs_subsys->fs_subsys);
cscfg_dev->cfgfs_subsys = NULL;
- }
- syscfg_fs_subsys.cfgdev = NULL;
+} diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.h b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h new file mode 100644 index 000000000000..70cc3745649e --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/*
- Coresight system configuration driver - support for configfs.
- */
+#ifndef CORESIGHT_SYSCFG_CONFIGFS_H +#define CORESIGHT_SYSCFG_CONFIGFS_H
+#include <linux/configfs.h> +#include "coresight-syscfg.h"
+/* container to associate the device and configfs subsystem */ +struct cscfg_fs_subsys {
- struct cscfg_device *cfgdev;
- struct configfs_subsystem fs_subsys;
+};
+/* container for default groups */ +struct cscfg_fs_def_group {
- struct config_group group;
+};
Please don't do that - there is enough new structures in this patchset as it is.
+/* container for configuration view */ +struct cscfg_fs_config {
- struct cscfg_config_desc *desc;
- struct config_group group;
+};
+/* container for feature view */ +struct cscfg_fs_feature {
- struct cscfg_feature_desc *desc;
- struct config_group group;
+};
+/* container for parameter view */ +struct cscfg_fs_param {
- struct cscfg_parameter_desc *param;
- struct cscfg_feature_desc *desc;
- struct config_group group;
+};
+int cscfg_configfs_init(struct cscfg_device *dev); +void cscfg_configfs_release(struct cscfg_device *dev); +int cscfg_configfs_add_config(struct cscfg_config_desc *cfg_desc); +int cscfg_configfs_add_feature(struct cscfg_feature_desc *feat_desc);
+#endif /* CORESIGHT_SYSCFG_CONFIGFS_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 8d52580daf04..2cf67a038cc8 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -9,6 +9,7 @@ #include "coresight-config.h" #include "coresight-etm-perf.h" #include "coresight-syscfg.h" +#include "coresight-syscfg-configfs.h" /*
- cscfg_ API manages configurations and features for the entire coresight
@@ -260,6 +261,8 @@ static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc) { int err;
- spin_lock_init(&feat_desc->param_lock);
- /* add feature to any matching registered devices */ err = cscfg_add_feat_to_csdevs(feat_desc); if (err)
@@ -294,6 +297,24 @@ static int cscfg_load_config(struct cscfg_config_desc *cfg_desc) return err; } +/* get a feature descriptor by name */ +const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name) +{
- const struct cscfg_feature_desc *feat = NULL, *feat_item;
- mutex_lock(&cscfg_mutex);
- list_for_each_entry(feat_item, &cscfg_data.feat_list, item) {
if (strcmp(feat_item->name, name) == 0) {
feat = feat_item;
break;
}
- }
- mutex_unlock(&cscfg_mutex);
- return feat;
+}
/*
- External API function to load feature and config sets.
- Take a 0 terminated array of feature descriptors and/or configuration
@@ -316,6 +337,7 @@ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, feat_descs[i]->name); goto do_unlock; }
} }cscfg_configfs_add_feature(feat_descs[i]); i++;
@@ -330,6 +352,7 @@ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, cfg_descs[i]->name); goto do_unlock; }
} }cscfg_configfs_add_config(cfg_descs[i]); i++;
@@ -502,6 +525,7 @@ struct device *to_device_cscfg(void) /* Must have a release function or the kernel will complain on module unload */ void cscfg_dev_release(struct device *dev) {
- cscfg_configfs_release(cscfg_dev); kfree(cscfg_dev); cscfg_dev = NULL;
} @@ -530,6 +554,7 @@ int cscfg_create_device(void) cscfg_dev->cfg_data = &cscfg_data; err = device_register(dev);
Extra line
if (err) cscfg_dev_release(dev); @@ -587,6 +612,10 @@ int __init cscfg_init(void) if (err) goto exit_drv_unregister;
- err = cscfg_configfs_init(cscfg_dev);
- if (err)
goto exit_dev_clear;
- INIT_LIST_HEAD(&cscfg_data.dev_list); INIT_LIST_HEAD(&cscfg_data.feat_list); INIT_LIST_HEAD(&cscfg_data.config_list);
@@ -595,6 +624,8 @@ int __init cscfg_init(void) dev_info(to_device_cscfg(), "CoreSight Configuration manager initialised"); return 0; +exit_dev_clear:
- cscfg_clear_device();
exit_drv_unregister: cscfg_driver_exit(); exit_bus_unregister: diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index e8f352599dd7..ce237a69677b 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -6,6 +6,7 @@ #ifndef CORESIGHT_SYSCFG_H #define CORESIGHT_SYSCFG_H +#include <linux/configfs.h>
Same here, I don't see what this header file is adding.
I'm out of time for today and will continue with the rest of this patch tomorrow.
Thanks, Mathieu
#include <linux/coresight.h> #include <linux/device.h> @@ -46,6 +47,7 @@ struct cscfg_csdev_register { int __init cscfg_init(void); void __exit cscfg_exit(void); int cscfg_preload(void); +const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name); /* syscfg external API */ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, @@ -64,10 +66,12 @@ void cscfg_unregister_csdev(struct coresight_device *csdev);
- @dev: The device.
- @cfg_data: A reference to the configuration and feature lists
*/
- @cfgfs_subsys: configfs subsystem used to manage configurations.
struct cscfg_device { struct device dev; struct cscfg_api_data *cfg_data;
- struct cscfg_fs_subsys *cfgfs_subsys;
}; /* basic device driver */ -- 2.17.1
On Fri, Oct 30, 2020 at 05:56:53PM +0000, Mike Leach wrote:
Adds configfs subsystem and attributes to the configuration manager to enable the listing of loaded configurations and features.
The default values of feature parameters can be accessed and altered from these attributes to affect all installed devices using the feature.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 2 +- .../hwtracing/coresight/coresight-config.c | 2 + .../hwtracing/coresight/coresight-config.h | 5 +- .../coresight/coresight-syscfg-configfs.c | 418 ++++++++++++++++++ .../coresight/coresight-syscfg-configfs.h | 47 ++ .../hwtracing/coresight/coresight-syscfg.c | 31 ++ .../hwtracing/coresight/coresight-syscfg.h | 4 + 7 files changed, 507 insertions(+), 2 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-syscfg-configfs.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg-configfs.h
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 9de5586cfd1a..4ec226c44f5b 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \ coresight-sysfs.o coresight-syscfg.o coresight-config.o \
coresight-cfg-preload.o
coresight-cfg-preload.o coresight-syscfg-configfs.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-config.c b/drivers/hwtracing/coresight/coresight-config.c index d911e0f083c1..04e7cb4ff769 100644 --- a/drivers/hwtracing/coresight/coresight-config.c +++ b/drivers/hwtracing/coresight/coresight-config.c @@ -111,8 +111,10 @@ static void cscfg_reset_feat(struct cscfg_feature_csdev *feat) * set the default values for all parameters and regs from the * relevant static descriptors. */
- spin_lock(&feat->desc->param_lock); for (i = 0; i < feat->nr_params; i++) feat->params[i].current_value = feat->desc->params[i].value;
- spin_unlock(&feat->desc->param_lock);
for (i = 0; i < feat->nr_regs; i++) { reg_desc = &feat->desc->regs[i]; diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 372f29a59688..39fcac011aa0 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -7,6 +7,7 @@ #ifndef _CORESIGHT_CORESIGHT_CONFIG_H #define _CORESIGHT_CORESIGHT_CONFIG_H +#include <linux/configfs.h> #include <linux/coresight.h> #include <linux/types.h> @@ -89,6 +90,7 @@ struct cscfg_regval {
- @match_flags: matching information if loading into a device
- @nr_params: number of parameters used.
- @params: array of parameters used.
*/
- @param_lock: protect params when accessing default values.
- @nr_regs: number of registers used.
- @reg: array of registers used.
@@ -99,6 +101,7 @@ struct cscfg_feature_desc { u32 match_flags; int nr_params; struct cscfg_parameter_desc *params;
- spinlock_t param_lock; int nr_regs; struct cscfg_regval *regs;
}; @@ -239,7 +242,7 @@ struct cscfg_feat_ops {
- @ops: standard ops to enable and disable features on devices.
*/ struct cscfg_feature_csdev {
- const struct cscfg_feature_desc *desc;
- struct cscfg_feature_desc *desc; struct coresight_device *csdev; struct list_head node; spinlock_t *csdev_spinlock;
diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c new file mode 100644 index 000000000000..ff7ea678100a --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c @@ -0,0 +1,418 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <linux/configfs.h>
+#include "coresight-syscfg-configfs.h"
+/*
- configfs support for syscfg device.
- config fs is used to manage configurations and features on the
- coresight system.
- */
+static struct cscfg_device *cscfg_fs_get_cscfg_dev(void);
+static struct device *cscfg_dev_to_dev(void) +{
- return cscfg_fs_get_cscfg_dev() ? &cscfg_fs_get_cscfg_dev()->dev : NULL;
+}
+/*
- Declare the subsystem - with base attributes allowing listing of
- loaded configurations
- */
+static inline struct cscfg_fs_config *to_cscfg_fs_config_group(struct config_group *group) +{
- return container_of(group, struct cscfg_fs_config, group);
Please just call container_of() when needed, it is much easier to understand.
+}
+/* configurations sub-group */
+/* attributes for the config view group */ +static ssize_t cscfg_cfg_description_show(struct config_item *item, char *page) +{
- struct cscfg_fs_config *fs_config = to_cscfg_fs_config_group(to_config_group(item));
- return scnprintf(page, PAGE_SIZE, "%s\n", fs_config->desc->brief);
+} +CONFIGFS_ATTR_RO(cscfg_cfg_, description);
+static ssize_t cscfg_cfg_refs_show(struct config_item *item, char *page) +{
- struct cscfg_fs_config *fs_config = to_cscfg_fs_config_group(to_config_group(item));
- const struct cscfg_config_desc *desc = fs_config->desc;
- ssize_t ch_used = 0;
- int i;
- if (desc->nr_refs) {
ch_used += scnprintf(page, PAGE_SIZE, "references %d features:-\n", desc->nr_refs);
I would remove the above as it makes things harder to parse from a script.
for (i = 0; i < desc->nr_refs; i++) {
ch_used += scnprintf(page + ch_used, PAGE_SIZE - ch_used,
"%s\n", desc->refs[i].name);
}
- } else
ch_used = scnprintf(page, PAGE_SIZE, "no features referenced\n");
- return ch_used;
+} +CONFIGFS_ATTR_RO(cscfg_cfg_, refs);
+static ssize_t cscfg_cfg_nr_presets_show(struct config_item *item, char *page) +{
- struct cscfg_fs_config *fs_config = to_cscfg_fs_config_group(to_config_group(item));
- return scnprintf(page, PAGE_SIZE, "%d\n", fs_config->desc->nr_presets);
+} +CONFIGFS_ATTR_RO(cscfg_cfg_, nr_presets);
I wouldn't bother showing the presets - that information is already available in "preset_values".
+static ssize_t cscfg_cfg_preset_values_show(struct config_item *item, char *page) +{
- struct cscfg_fs_config *fs_config = to_cscfg_fs_config_group(to_config_group(item));
- const struct cscfg_config_desc *cfg = fs_config->desc;
- const struct cscfg_feature_desc *feat;
- ssize_t used = 0;
- int i, j, val_idx, preset_idx;
- if (!fs_config->desc->nr_presets)
return scnprintf(page, PAGE_SIZE, "No presets defined\n");
Pseudo file systems don't show anything when no entries are available.
- used = scnprintf(page, PAGE_SIZE, "%d presets, %d parameters per preset\n",
fs_config->desc->nr_presets, cfg->nr_total_params);
Same here, pseudo file systems are usually not chatty.
- for (preset_idx = 0; preset_idx < fs_config->desc->nr_presets; preset_idx++) {
/* start index on the correct array line */
val_idx = cfg->nr_total_params * preset_idx;
/* preset indexes are used as 1 based by the user */
used += scnprintf(page + used, PAGE_SIZE - used, "preset[%d]: ", preset_idx+1);
/*
* A set of presets is the sum of all params in used features,
* in order of declaration of features and params in the features
*/
for (i = 0; i < cfg->nr_refs; i++) {
feat = cscfg_get_named_feat_desc(cfg->refs[i].name);
for (j = 0; j < cfg->refs[i].nr_params; j++) {
used += scnprintf(page + used, PAGE_SIZE - used,
"%s.%s = 0x%llx ",
cfg->refs[i].name, feat->params[j].name,
cfg->presets[val_idx++]);
}
}
used += scnprintf(page + used, PAGE_SIZE - used, "\n");
I'm weary the above doesn't scale well when multiple features, each with their own parameters are present. Here is a suggestion:
root@linaro:/sys/kernel/config/coresight-syscfg/configurations/autofdo# cat presets preset0 preset1 preset2
root@linaro:/sys/kernel/config/coresight-syscfg/configurations/autofdo# cd preset1 root@linaro:/sys/kernel/config/coresight-syscfg/configurations/autofdo/preset1# ls strobing root@linaro:/sys/kernel/config/coresight-syscfg/configurations/autofdo/preset1# cd strobing root@linaro:/sys/kernel/config/coresight-syscfg/configurations/autofdo/preset1/strobing# ls window period
It is more cumbersome but guaranteed to work with any number of features and parameters.
- }
- return used;
+} +CONFIGFS_ATTR_RO(cscfg_cfg_, preset_values);
+static struct configfs_attribute *cscfg_config_view_attrs[] = {
- &cscfg_cfg_attr_description,
- &cscfg_cfg_attr_refs,
- &cscfg_cfg_attr_nr_presets,
- &cscfg_cfg_attr_preset_values,
- NULL,
+};
+static struct config_item_type cscfg_config_view_type = {
- .ct_owner = THIS_MODULE,
- .ct_attrs = cscfg_config_view_attrs,
+};
+static struct config_group *cscfg_create_config_group(struct cscfg_config_desc *cfg_desc) +{
- struct cscfg_fs_config *cfg_view;
- struct device *dev = cscfg_dev_to_dev();
- if (!dev)
return ERR_PTR(-EINVAL);
- cfg_view = devm_kzalloc(dev, sizeof(struct cscfg_fs_config), GFP_KERNEL);
- if (!cfg_view)
return ERR_PTR(-ENOMEM);
- cfg_view->desc = cfg_desc;
- config_group_init_type_name(&cfg_view->group, cfg_desc->name, &cscfg_config_view_type);
- return &cfg_view->group;
+}
+static struct config_item_type cscfg_configs_type = {
- .ct_owner = THIS_MODULE,
+};
+static struct cscfg_fs_def_group cscfg_configs_grp = {
- .group = {
.cg_item = {
.ci_namebuf = "configurations",
.ci_type = &cscfg_configs_type,
},
- },
+};
+/* attributes for features view */
+static inline struct cscfg_fs_feature *to_cscfg_fs_feature_group(struct config_group *group) +{
- return container_of(group, struct cscfg_fs_feature, group);
+}
+static ssize_t cscfg_feat_description_show(struct config_item *item, char *page) +{
- struct cscfg_fs_feature *fs_feat = to_cscfg_fs_feature_group(to_config_group(item));
- return scnprintf(page, PAGE_SIZE, "%s\n", fs_feat->desc->brief);
+} +CONFIGFS_ATTR_RO(cscfg_feat_, description);
+static ssize_t cscfg_feat_matches_show(struct config_item *item, char *page) +{
- struct cscfg_fs_feature *fs_feat = to_cscfg_fs_feature_group(to_config_group(item));
- u32 match_flags = fs_feat->desc->match_flags;
- int used = 0;
- if (match_flags & CS_CFG_MATCH_CLASS_SRC_ALL)
used = scnprintf(page, PAGE_SIZE, "SRC_ALL ");
- if (match_flags & CS_CFG_MATCH_CLASS_SRC_ETM4)
used += scnprintf(page + used, PAGE_SIZE - used, "SRC_ETMV4 ");
- if (match_flags & CS_CFG_MATCH_CLASS_CTI_ALL)
used += scnprintf(page + used, PAGE_SIZE - used, "CTI_ALL ");
- if (match_flags & CS_CFG_MATCH_CLASS_CTI_CPU)
used += scnprintf(page + used, PAGE_SIZE - used, "CTI_CPU ");
- if (match_flags & CS_CFG_MATCH_CLASS_CTI_SYS)
used += scnprintf(page + used, PAGE_SIZE - used, "CTI_SYS ");
- used += scnprintf(page + used, PAGE_SIZE - used, "\n");
- return used;
+} +CONFIGFS_ATTR_RO(cscfg_feat_, matches);
+static ssize_t cscfg_feat_nr_params_show(struct config_item *item, char *page) +{
- struct cscfg_fs_feature *fs_feat = to_cscfg_fs_feature_group(to_config_group(item));
- return scnprintf(page, PAGE_SIZE, "%d\n", fs_feat->desc->nr_params);
+} +CONFIGFS_ATTR_RO(cscfg_feat_, nr_params);
+/* base feature desc attrib structures */ +static struct configfs_attribute *cscfg_feature_view_attrs[] = {
- &cscfg_feat_attr_description,
- &cscfg_feat_attr_matches,
- &cscfg_feat_attr_nr_params,
Did you have a specific need for nr_params? To me it can be removed.
- NULL,
+};
+static struct config_item_type cscfg_feature_view_type = {
- .ct_owner = THIS_MODULE,
- .ct_attrs = cscfg_feature_view_attrs,
+};
+static inline struct cscfg_fs_param *to_cscfg_fs_param_group(struct config_group *group) +{
- return container_of(group, struct cscfg_fs_param, group);
+}
+static ssize_t cscfg_param_value_show(struct config_item *item, char *page) +{
- struct cscfg_fs_param *param_item = to_cscfg_fs_param_group(to_config_group(item));
- return scnprintf(page, PAGE_SIZE, "0x%llx\n", param_item->param->value);
+}
+static ssize_t cscfg_param_value_store(struct config_item *item,
const char *page, size_t size)
+{
- struct cscfg_fs_param *param_item = to_cscfg_fs_param_group(to_config_group(item));
I would much rather see a direct call to container_of() than a new function that calls container_of()...
- u64 val;
- int err;
- err = kstrtoull(page, 0, &val);
- if (err)
return err;
- spin_lock(¶m_item->desc->param_lock);
- param_item->param->value = val;
- spin_unlock(¶m_item->desc->param_lock);
- return size;
+} +CONFIGFS_ATTR(cscfg_param_, value);
+static struct configfs_attribute *cscfg_param_view_attrs[] = {
- &cscfg_param_attr_value,
- NULL,
+};
+static struct config_item_type cscfg_param_view_type = {
- .ct_owner = THIS_MODULE,
- .ct_attrs = cscfg_param_view_attrs,
+};
+static struct config_item_type cscfg_feat_param_group_type = {
- .ct_owner = THIS_MODULE,
Out of curiosity, what happens if .ct_owner isn't set to THIS_MODULE?
Thanks, Mathieu
+};
+/*
- configfs has far less functionality provided to add attributes dynamically than sysfs,
- and the show and store fns pass the enclosing config_item so the actual attribute cannot
- be determined. Therefore we add each item as a group directory, with a value attribute.
- */
+static int cscfg_create_params_group_items(struct cscfg_feature_desc *feat_desc,
struct config_group *params_group)
+{
- struct device *dev = cscfg_dev_to_dev();
- struct cscfg_fs_param *param_item;
- int i;
- /* parameter items - as groups with default_value attribute */
- for (i = 0; i < feat_desc->nr_params; i++) {
param_item = devm_kzalloc(dev, sizeof(struct cscfg_fs_param), GFP_KERNEL);
if (!param_item)
return -ENOMEM;
param_item->desc = feat_desc;
param_item->param = &feat_desc->params[i];
config_group_init_type_name(¶m_item->group, param_item->param->name,
&cscfg_param_view_type);
configfs_add_default_group(¶m_item->group, params_group);
- }
- return 0;
+}
+static struct config_group *cscfg_create_feature_group(struct cscfg_feature_desc *feat_desc) +{
- struct cscfg_fs_feature *feat_view;
- struct device *dev = cscfg_dev_to_dev();
- struct cscfg_fs_def_group *params_group = NULL;
- int item_err;
- if (!dev)
return ERR_PTR(-EINVAL);
- feat_view = devm_kzalloc(dev, sizeof(struct cscfg_fs_feature), GFP_KERNEL);
- if (!feat_view)
return ERR_PTR(-ENOMEM);
- if (feat_desc->nr_params) {
params_group = devm_kzalloc(dev, sizeof(struct cscfg_fs_feature), GFP_KERNEL);
if (!params_group)
return ERR_PTR(-ENOMEM);
- }
- feat_view->desc = feat_desc;
- config_group_init_type_name(&feat_view->group,
feat_desc->name,
&cscfg_feature_view_type);
- if (params_group) {
config_group_init_type_name(¶ms_group->group, "params",
&cscfg_feat_param_group_type);
configfs_add_default_group(¶ms_group->group, &feat_view->group);
item_err = cscfg_create_params_group_items(feat_desc, ¶ms_group->group);
if (item_err)
return ERR_PTR(item_err);
- }
- return &feat_view->group;
+}
+static struct config_item_type cscfg_features_type = {
- .ct_owner = THIS_MODULE,
+};
+static struct cscfg_fs_def_group cscfg_features_grp = {
- .group = {
.cg_item = {
.ci_namebuf = "features",
.ci_type = &cscfg_features_type,
},
- },
+};
+/* add configuration to configurations group */ +int cscfg_configfs_add_config(struct cscfg_config_desc *cfg_desc) +{
- struct config_group *new_group;
- int err;
- new_group = cscfg_create_config_group(cfg_desc);
- if (IS_ERR(new_group))
return PTR_ERR(new_group);
- err = configfs_register_group(&cscfg_configs_grp.group, new_group);
- return err;
+}
+/* add feature to features group */ +int cscfg_configfs_add_feature(struct cscfg_feature_desc *feat_desc) +{
- struct config_group *new_group;
- int err;
- new_group = cscfg_create_feature_group(feat_desc);
- if (IS_ERR(new_group))
return PTR_ERR(new_group);
- err = configfs_register_group(&cscfg_features_grp.group, new_group);
- return err;
+}
+static const struct config_item_type syscfg_fs_type = {
- .ct_owner = THIS_MODULE,
+};
+static struct cscfg_fs_subsys syscfg_fs_subsys = {
- .cfgdev = NULL,
- .fs_subsys = {
.su_group = {
.cg_item = {
.ci_namebuf = "coresight-syscfg",
.ci_type = &syscfg_fs_type,
},
},
- },
+};
+static inline struct cscfg_device *cscfg_fs_get_cscfg_dev(void) +{
- return syscfg_fs_subsys.cfgdev;
+}
+int cscfg_configfs_init(struct cscfg_device *cscfg_dev) +{
- int ret = 0;
- struct configfs_subsystem *subsys = &syscfg_fs_subsys.fs_subsys;
- if (!cscfg_dev)
return -EINVAL;
- config_group_init(&subsys->su_group);
- mutex_init(&subsys->su_mutex);
- /* Add default groups to subsystem */
- config_group_init(&cscfg_configs_grp.group);
- configfs_add_default_group(&cscfg_configs_grp.group, &subsys->su_group);
- config_group_init(&cscfg_features_grp.group);
- configfs_add_default_group(&cscfg_features_grp.group, &subsys->su_group);
- ret = configfs_register_subsystem(subsys);
- if (!ret) {
syscfg_fs_subsys.cfgdev = cscfg_dev;
cscfg_dev->cfgfs_subsys = &syscfg_fs_subsys;
- }
- return ret;
+}
+void cscfg_configfs_release(struct cscfg_device *cscfg_dev) +{
- if (cscfg_dev && cscfg_dev->cfgfs_subsys) {
configfs_unregister_subsystem(&cscfg_dev->cfgfs_subsys->fs_subsys);
cscfg_dev->cfgfs_subsys = NULL;
- }
- syscfg_fs_subsys.cfgdev = NULL;
+} diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.h b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h new file mode 100644 index 000000000000..70cc3745649e --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/*
- Coresight system configuration driver - support for configfs.
- */
+#ifndef CORESIGHT_SYSCFG_CONFIGFS_H +#define CORESIGHT_SYSCFG_CONFIGFS_H
+#include <linux/configfs.h> +#include "coresight-syscfg.h"
+/* container to associate the device and configfs subsystem */ +struct cscfg_fs_subsys {
- struct cscfg_device *cfgdev;
- struct configfs_subsystem fs_subsys;
+};
+/* container for default groups */ +struct cscfg_fs_def_group {
- struct config_group group;
+};
+/* container for configuration view */ +struct cscfg_fs_config {
- struct cscfg_config_desc *desc;
- struct config_group group;
+};
+/* container for feature view */ +struct cscfg_fs_feature {
- struct cscfg_feature_desc *desc;
- struct config_group group;
+};
+/* container for parameter view */ +struct cscfg_fs_param {
- struct cscfg_parameter_desc *param;
- struct cscfg_feature_desc *desc;
- struct config_group group;
+};
+int cscfg_configfs_init(struct cscfg_device *dev); +void cscfg_configfs_release(struct cscfg_device *dev); +int cscfg_configfs_add_config(struct cscfg_config_desc *cfg_desc); +int cscfg_configfs_add_feature(struct cscfg_feature_desc *feat_desc);
+#endif /* CORESIGHT_SYSCFG_CONFIGFS_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 8d52580daf04..2cf67a038cc8 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -9,6 +9,7 @@ #include "coresight-config.h" #include "coresight-etm-perf.h" #include "coresight-syscfg.h" +#include "coresight-syscfg-configfs.h" /*
- cscfg_ API manages configurations and features for the entire coresight
@@ -260,6 +261,8 @@ static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc) { int err;
- spin_lock_init(&feat_desc->param_lock);
- /* add feature to any matching registered devices */ err = cscfg_add_feat_to_csdevs(feat_desc); if (err)
@@ -294,6 +297,24 @@ static int cscfg_load_config(struct cscfg_config_desc *cfg_desc) return err; } +/* get a feature descriptor by name */ +const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name) +{
- const struct cscfg_feature_desc *feat = NULL, *feat_item;
- mutex_lock(&cscfg_mutex);
- list_for_each_entry(feat_item, &cscfg_data.feat_list, item) {
if (strcmp(feat_item->name, name) == 0) {
feat = feat_item;
break;
}
- }
- mutex_unlock(&cscfg_mutex);
- return feat;
+}
/*
- External API function to load feature and config sets.
- Take a 0 terminated array of feature descriptors and/or configuration
@@ -316,6 +337,7 @@ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, feat_descs[i]->name); goto do_unlock; }
} }cscfg_configfs_add_feature(feat_descs[i]); i++;
@@ -330,6 +352,7 @@ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, cfg_descs[i]->name); goto do_unlock; }
} }cscfg_configfs_add_config(cfg_descs[i]); i++;
@@ -502,6 +525,7 @@ struct device *to_device_cscfg(void) /* Must have a release function or the kernel will complain on module unload */ void cscfg_dev_release(struct device *dev) {
- cscfg_configfs_release(cscfg_dev); kfree(cscfg_dev); cscfg_dev = NULL;
} @@ -530,6 +554,7 @@ int cscfg_create_device(void) cscfg_dev->cfg_data = &cscfg_data; err = device_register(dev);
- if (err) cscfg_dev_release(dev);
@@ -587,6 +612,10 @@ int __init cscfg_init(void) if (err) goto exit_drv_unregister;
- err = cscfg_configfs_init(cscfg_dev);
- if (err)
goto exit_dev_clear;
- INIT_LIST_HEAD(&cscfg_data.dev_list); INIT_LIST_HEAD(&cscfg_data.feat_list); INIT_LIST_HEAD(&cscfg_data.config_list);
@@ -595,6 +624,8 @@ int __init cscfg_init(void) dev_info(to_device_cscfg(), "CoreSight Configuration manager initialised"); return 0; +exit_dev_clear:
- cscfg_clear_device();
exit_drv_unregister: cscfg_driver_exit(); exit_bus_unregister: diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index e8f352599dd7..ce237a69677b 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -6,6 +6,7 @@ #ifndef CORESIGHT_SYSCFG_H #define CORESIGHT_SYSCFG_H +#include <linux/configfs.h> #include <linux/coresight.h> #include <linux/device.h> @@ -46,6 +47,7 @@ struct cscfg_csdev_register { int __init cscfg_init(void); void __exit cscfg_exit(void); int cscfg_preload(void); +const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name); /* syscfg external API */ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, @@ -64,10 +66,12 @@ void cscfg_unregister_csdev(struct coresight_device *csdev);
- @dev: The device.
- @cfg_data: A reference to the configuration and feature lists
*/
- @cfgfs_subsys: configfs subsystem used to manage configurations.
struct cscfg_device { struct device dev; struct cscfg_api_data *cfg_data;
- struct cscfg_fs_subsys *cfgfs_subsys;
}; /* basic device driver */ -- 2.17.1
On Fri, Oct 30, 2020 at 05:56:53PM +0000, Mike Leach wrote:
Adds configfs subsystem and attributes to the configuration manager to enable the listing of loaded configurations and features.
The default values of feature parameters can be accessed and altered from these attributes to affect all installed devices using the feature.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 2 +- .../hwtracing/coresight/coresight-config.c | 2 + .../hwtracing/coresight/coresight-config.h | 5 +- .../coresight/coresight-syscfg-configfs.c | 418 ++++++++++++++++++ .../coresight/coresight-syscfg-configfs.h | 47 ++ .../hwtracing/coresight/coresight-syscfg.c | 31 ++ .../hwtracing/coresight/coresight-syscfg.h | 4 + 7 files changed, 507 insertions(+), 2 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-syscfg-configfs.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg-configfs.h
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 9de5586cfd1a..4ec226c44f5b 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \ coresight-sysfs.o coresight-syscfg.o coresight-config.o \
coresight-cfg-preload.o
coresight-cfg-preload.o coresight-syscfg-configfs.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-config.c b/drivers/hwtracing/coresight/coresight-config.c index d911e0f083c1..04e7cb4ff769 100644 --- a/drivers/hwtracing/coresight/coresight-config.c +++ b/drivers/hwtracing/coresight/coresight-config.c @@ -111,8 +111,10 @@ static void cscfg_reset_feat(struct cscfg_feature_csdev *feat) * set the default values for all parameters and regs from the * relevant static descriptors. */
- spin_lock(&feat->desc->param_lock); for (i = 0; i < feat->nr_params; i++) feat->params[i].current_value = feat->desc->params[i].value;
- spin_unlock(&feat->desc->param_lock);
for (i = 0; i < feat->nr_regs; i++) { reg_desc = &feat->desc->regs[i]; diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 372f29a59688..39fcac011aa0 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -7,6 +7,7 @@ #ifndef _CORESIGHT_CORESIGHT_CONFIG_H #define _CORESIGHT_CORESIGHT_CONFIG_H +#include <linux/configfs.h> #include <linux/coresight.h> #include <linux/types.h> @@ -89,6 +90,7 @@ struct cscfg_regval {
- @match_flags: matching information if loading into a device
- @nr_params: number of parameters used.
- @params: array of parameters used.
*/
- @param_lock: protect params when accessing default values.
- @nr_regs: number of registers used.
- @reg: array of registers used.
@@ -99,6 +101,7 @@ struct cscfg_feature_desc { u32 match_flags; int nr_params; struct cscfg_parameter_desc *params;
- spinlock_t param_lock; int nr_regs; struct cscfg_regval *regs;
}; @@ -239,7 +242,7 @@ struct cscfg_feat_ops {
- @ops: standard ops to enable and disable features on devices.
*/ struct cscfg_feature_csdev {
- const struct cscfg_feature_desc *desc;
- struct cscfg_feature_desc *desc; struct coresight_device *csdev; struct list_head node; spinlock_t *csdev_spinlock;
diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c new file mode 100644 index 000000000000..ff7ea678100a --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c @@ -0,0 +1,418 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <linux/configfs.h>
+#include "coresight-syscfg-configfs.h"
+/*
- configfs support for syscfg device.
- config fs is used to manage configurations and features on the
- coresight system.
- */
+static struct cscfg_device *cscfg_fs_get_cscfg_dev(void);
+static struct device *cscfg_dev_to_dev(void) +{
- return cscfg_fs_get_cscfg_dev() ? &cscfg_fs_get_cscfg_dev()->dev : NULL;
+}
+/*
- Declare the subsystem - with base attributes allowing listing of
- loaded configurations
- */
+static inline struct cscfg_fs_config *to_cscfg_fs_config_group(struct config_group *group) +{
- return container_of(group, struct cscfg_fs_config, group);
+}
+/* configurations sub-group */
+/* attributes for the config view group */ +static ssize_t cscfg_cfg_description_show(struct config_item *item, char *page) +{
- struct cscfg_fs_config *fs_config = to_cscfg_fs_config_group(to_config_group(item));
- return scnprintf(page, PAGE_SIZE, "%s\n", fs_config->desc->brief);
+} +CONFIGFS_ATTR_RO(cscfg_cfg_, description);
+static ssize_t cscfg_cfg_refs_show(struct config_item *item, char *page) +{
- struct cscfg_fs_config *fs_config = to_cscfg_fs_config_group(to_config_group(item));
- const struct cscfg_config_desc *desc = fs_config->desc;
- ssize_t ch_used = 0;
- int i;
- if (desc->nr_refs) {
ch_used += scnprintf(page, PAGE_SIZE, "references %d features:-\n", desc->nr_refs);
for (i = 0; i < desc->nr_refs; i++) {
ch_used += scnprintf(page + ch_used, PAGE_SIZE - ch_used,
"%s\n", desc->refs[i].name);
}
- } else
ch_used = scnprintf(page, PAGE_SIZE, "no features referenced\n");
- return ch_used;
+} +CONFIGFS_ATTR_RO(cscfg_cfg_, refs);
+static ssize_t cscfg_cfg_nr_presets_show(struct config_item *item, char *page) +{
- struct cscfg_fs_config *fs_config = to_cscfg_fs_config_group(to_config_group(item));
- return scnprintf(page, PAGE_SIZE, "%d\n", fs_config->desc->nr_presets);
+} +CONFIGFS_ATTR_RO(cscfg_cfg_, nr_presets);
+static ssize_t cscfg_cfg_preset_values_show(struct config_item *item, char *page) +{
- struct cscfg_fs_config *fs_config = to_cscfg_fs_config_group(to_config_group(item));
- const struct cscfg_config_desc *cfg = fs_config->desc;
- const struct cscfg_feature_desc *feat;
- ssize_t used = 0;
- int i, j, val_idx, preset_idx;
- if (!fs_config->desc->nr_presets)
return scnprintf(page, PAGE_SIZE, "No presets defined\n");
- used = scnprintf(page, PAGE_SIZE, "%d presets, %d parameters per preset\n",
fs_config->desc->nr_presets, cfg->nr_total_params);
- for (preset_idx = 0; preset_idx < fs_config->desc->nr_presets; preset_idx++) {
/* start index on the correct array line */
val_idx = cfg->nr_total_params * preset_idx;
/* preset indexes are used as 1 based by the user */
used += scnprintf(page + used, PAGE_SIZE - used, "preset[%d]: ", preset_idx+1);
/*
* A set of presets is the sum of all params in used features,
* in order of declaration of features and params in the features
*/
for (i = 0; i < cfg->nr_refs; i++) {
feat = cscfg_get_named_feat_desc(cfg->refs[i].name);
for (j = 0; j < cfg->refs[i].nr_params; j++) {
used += scnprintf(page + used, PAGE_SIZE - used,
"%s.%s = 0x%llx ",
cfg->refs[i].name, feat->params[j].name,
cfg->presets[val_idx++]);
}
}
used += scnprintf(page + used, PAGE_SIZE - used, "\n");
- }
- return used;
+} +CONFIGFS_ATTR_RO(cscfg_cfg_, preset_values);
+static struct configfs_attribute *cscfg_config_view_attrs[] = {
- &cscfg_cfg_attr_description,
- &cscfg_cfg_attr_refs,
- &cscfg_cfg_attr_nr_presets,
- &cscfg_cfg_attr_preset_values,
- NULL,
+};
+static struct config_item_type cscfg_config_view_type = {
- .ct_owner = THIS_MODULE,
- .ct_attrs = cscfg_config_view_attrs,
+};
+static struct config_group *cscfg_create_config_group(struct cscfg_config_desc *cfg_desc) +{
- struct cscfg_fs_config *cfg_view;
- struct device *dev = cscfg_dev_to_dev();
- if (!dev)
return ERR_PTR(-EINVAL);
- cfg_view = devm_kzalloc(dev, sizeof(struct cscfg_fs_config), GFP_KERNEL);
- if (!cfg_view)
return ERR_PTR(-ENOMEM);
- cfg_view->desc = cfg_desc;
- config_group_init_type_name(&cfg_view->group, cfg_desc->name, &cscfg_config_view_type);
- return &cfg_view->group;
+}
+static struct config_item_type cscfg_configs_type = {
- .ct_owner = THIS_MODULE,
+};
+static struct cscfg_fs_def_group cscfg_configs_grp = {
- .group = {
.cg_item = {
.ci_namebuf = "configurations",
.ci_type = &cscfg_configs_type,
},
- },
+};
+/* attributes for features view */
+static inline struct cscfg_fs_feature *to_cscfg_fs_feature_group(struct config_group *group) +{
- return container_of(group, struct cscfg_fs_feature, group);
+}
+static ssize_t cscfg_feat_description_show(struct config_item *item, char *page) +{
- struct cscfg_fs_feature *fs_feat = to_cscfg_fs_feature_group(to_config_group(item));
- return scnprintf(page, PAGE_SIZE, "%s\n", fs_feat->desc->brief);
+} +CONFIGFS_ATTR_RO(cscfg_feat_, description);
+static ssize_t cscfg_feat_matches_show(struct config_item *item, char *page) +{
- struct cscfg_fs_feature *fs_feat = to_cscfg_fs_feature_group(to_config_group(item));
- u32 match_flags = fs_feat->desc->match_flags;
- int used = 0;
- if (match_flags & CS_CFG_MATCH_CLASS_SRC_ALL)
used = scnprintf(page, PAGE_SIZE, "SRC_ALL ");
- if (match_flags & CS_CFG_MATCH_CLASS_SRC_ETM4)
used += scnprintf(page + used, PAGE_SIZE - used, "SRC_ETMV4 ");
- if (match_flags & CS_CFG_MATCH_CLASS_CTI_ALL)
used += scnprintf(page + used, PAGE_SIZE - used, "CTI_ALL ");
- if (match_flags & CS_CFG_MATCH_CLASS_CTI_CPU)
used += scnprintf(page + used, PAGE_SIZE - used, "CTI_CPU ");
- if (match_flags & CS_CFG_MATCH_CLASS_CTI_SYS)
used += scnprintf(page + used, PAGE_SIZE - used, "CTI_SYS ");
- used += scnprintf(page + used, PAGE_SIZE - used, "\n");
- return used;
+} +CONFIGFS_ATTR_RO(cscfg_feat_, matches);
+static ssize_t cscfg_feat_nr_params_show(struct config_item *item, char *page) +{
- struct cscfg_fs_feature *fs_feat = to_cscfg_fs_feature_group(to_config_group(item));
- return scnprintf(page, PAGE_SIZE, "%d\n", fs_feat->desc->nr_params);
+} +CONFIGFS_ATTR_RO(cscfg_feat_, nr_params);
+/* base feature desc attrib structures */ +static struct configfs_attribute *cscfg_feature_view_attrs[] = {
- &cscfg_feat_attr_description,
- &cscfg_feat_attr_matches,
- &cscfg_feat_attr_nr_params,
- NULL,
+};
+static struct config_item_type cscfg_feature_view_type = {
- .ct_owner = THIS_MODULE,
- .ct_attrs = cscfg_feature_view_attrs,
+};
+static inline struct cscfg_fs_param *to_cscfg_fs_param_group(struct config_group *group) +{
- return container_of(group, struct cscfg_fs_param, group);
+}
+static ssize_t cscfg_param_value_show(struct config_item *item, char *page) +{
- struct cscfg_fs_param *param_item = to_cscfg_fs_param_group(to_config_group(item));
- return scnprintf(page, PAGE_SIZE, "0x%llx\n", param_item->param->value);
+}
+static ssize_t cscfg_param_value_store(struct config_item *item,
const char *page, size_t size)
Indentation problem
+{
- struct cscfg_fs_param *param_item = to_cscfg_fs_param_group(to_config_group(item));
- u64 val;
- int err;
- err = kstrtoull(page, 0, &val);
- if (err)
return err;
- spin_lock(¶m_item->desc->param_lock);
- param_item->param->value = val;
- spin_unlock(¶m_item->desc->param_lock);
- return size;
+} +CONFIGFS_ATTR(cscfg_param_, value);
+static struct configfs_attribute *cscfg_param_view_attrs[] = {
- &cscfg_param_attr_value,
- NULL,
+};
+static struct config_item_type cscfg_param_view_type = {
- .ct_owner = THIS_MODULE,
- .ct_attrs = cscfg_param_view_attrs,
+};
+static struct config_item_type cscfg_feat_param_group_type = {
- .ct_owner = THIS_MODULE,
+};
+/*
- configfs has far less functionality provided to add attributes dynamically than sysfs,
- and the show and store fns pass the enclosing config_item so the actual attribute cannot
- be determined. Therefore we add each item as a group directory, with a value attribute.
- */
+static int cscfg_create_params_group_items(struct cscfg_feature_desc *feat_desc,
struct config_group *params_group)
+{
- struct device *dev = cscfg_dev_to_dev();
- struct cscfg_fs_param *param_item;
- int i;
- /* parameter items - as groups with default_value attribute */
- for (i = 0; i < feat_desc->nr_params; i++) {
param_item = devm_kzalloc(dev, sizeof(struct cscfg_fs_param), GFP_KERNEL);
if (!param_item)
return -ENOMEM;
param_item->desc = feat_desc;
param_item->param = &feat_desc->params[i];
config_group_init_type_name(¶m_item->group, param_item->param->name,
&cscfg_param_view_type);
configfs_add_default_group(¶m_item->group, params_group);
- }
- return 0;
+}
+static struct config_group *cscfg_create_feature_group(struct cscfg_feature_desc *feat_desc) +{
- struct cscfg_fs_feature *feat_view;
- struct device *dev = cscfg_dev_to_dev();
- struct cscfg_fs_def_group *params_group = NULL;
- int item_err;
- if (!dev)
return ERR_PTR(-EINVAL);
- feat_view = devm_kzalloc(dev, sizeof(struct cscfg_fs_feature), GFP_KERNEL);
- if (!feat_view)
return ERR_PTR(-ENOMEM);
- if (feat_desc->nr_params) {
params_group = devm_kzalloc(dev, sizeof(struct cscfg_fs_feature), GFP_KERNEL);
if (!params_group)
return ERR_PTR(-ENOMEM);
- }
- feat_view->desc = feat_desc;
- config_group_init_type_name(&feat_view->group,
feat_desc->name,
&cscfg_feature_view_type);
- if (params_group) {
config_group_init_type_name(¶ms_group->group, "params",
&cscfg_feat_param_group_type);
configfs_add_default_group(¶ms_group->group, &feat_view->group);
item_err = cscfg_create_params_group_items(feat_desc, ¶ms_group->group);
if (item_err)
return ERR_PTR(item_err);
- }
- return &feat_view->group;
+}
+static struct config_item_type cscfg_features_type = {
- .ct_owner = THIS_MODULE,
+};
+static struct cscfg_fs_def_group cscfg_features_grp = {
- .group = {
.cg_item = {
.ci_namebuf = "features",
.ci_type = &cscfg_features_type,
},
- },
+};
+/* add configuration to configurations group */ +int cscfg_configfs_add_config(struct cscfg_config_desc *cfg_desc) +{
- struct config_group *new_group;
- int err;
- new_group = cscfg_create_config_group(cfg_desc);
- if (IS_ERR(new_group))
return PTR_ERR(new_group);
- err = configfs_register_group(&cscfg_configs_grp.group, new_group);
- return err;
+}
+/* add feature to features group */ +int cscfg_configfs_add_feature(struct cscfg_feature_desc *feat_desc) +{
- struct config_group *new_group;
- int err;
- new_group = cscfg_create_feature_group(feat_desc);
- if (IS_ERR(new_group))
return PTR_ERR(new_group);
- err = configfs_register_group(&cscfg_features_grp.group, new_group);
- return err;
+}
+static const struct config_item_type syscfg_fs_type = {
- .ct_owner = THIS_MODULE,
+};
+static struct cscfg_fs_subsys syscfg_fs_subsys = {
- .cfgdev = NULL,
- .fs_subsys = {
.su_group = {
.cg_item = {
.ci_namebuf = "coresight-syscfg",
.ci_type = &syscfg_fs_type,
},
},
- },
+};
+static inline struct cscfg_device *cscfg_fs_get_cscfg_dev(void) +{
- return syscfg_fs_subsys.cfgdev;
+}
+int cscfg_configfs_init(struct cscfg_device *cscfg_dev) +{
- int ret = 0;
- struct configfs_subsystem *subsys = &syscfg_fs_subsys.fs_subsys;
- if (!cscfg_dev)
return -EINVAL;
- config_group_init(&subsys->su_group);
- mutex_init(&subsys->su_mutex);
- /* Add default groups to subsystem */
- config_group_init(&cscfg_configs_grp.group);
- configfs_add_default_group(&cscfg_configs_grp.group, &subsys->su_group);
- config_group_init(&cscfg_features_grp.group);
- configfs_add_default_group(&cscfg_features_grp.group, &subsys->su_group);
- ret = configfs_register_subsystem(subsys);
- if (!ret) {
syscfg_fs_subsys.cfgdev = cscfg_dev;
cscfg_dev->cfgfs_subsys = &syscfg_fs_subsys;
- }
- return ret;
+}
+void cscfg_configfs_release(struct cscfg_device *cscfg_dev) +{
- if (cscfg_dev && cscfg_dev->cfgfs_subsys) {
configfs_unregister_subsystem(&cscfg_dev->cfgfs_subsys->fs_subsys);
cscfg_dev->cfgfs_subsys = NULL;
- }
- syscfg_fs_subsys.cfgdev = NULL;
+} diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.h b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h new file mode 100644 index 000000000000..70cc3745649e --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/*
- Coresight system configuration driver - support for configfs.
- */
+#ifndef CORESIGHT_SYSCFG_CONFIGFS_H +#define CORESIGHT_SYSCFG_CONFIGFS_H
+#include <linux/configfs.h> +#include "coresight-syscfg.h"
+/* container to associate the device and configfs subsystem */ +struct cscfg_fs_subsys {
- struct cscfg_device *cfgdev;
- struct configfs_subsystem fs_subsys;
+};
+/* container for default groups */ +struct cscfg_fs_def_group {
- struct config_group group;
+};
+/* container for configuration view */ +struct cscfg_fs_config {
- struct cscfg_config_desc *desc;
- struct config_group group;
+};
+/* container for feature view */ +struct cscfg_fs_feature {
- struct cscfg_feature_desc *desc;
- struct config_group group;
+};
+/* container for parameter view */ +struct cscfg_fs_param {
- struct cscfg_parameter_desc *param;
- struct cscfg_feature_desc *desc;
- struct config_group group;
+};
+int cscfg_configfs_init(struct cscfg_device *dev); +void cscfg_configfs_release(struct cscfg_device *dev); +int cscfg_configfs_add_config(struct cscfg_config_desc *cfg_desc); +int cscfg_configfs_add_feature(struct cscfg_feature_desc *feat_desc);
+#endif /* CORESIGHT_SYSCFG_CONFIGFS_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 8d52580daf04..2cf67a038cc8 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -9,6 +9,7 @@ #include "coresight-config.h" #include "coresight-etm-perf.h" #include "coresight-syscfg.h" +#include "coresight-syscfg-configfs.h" /*
- cscfg_ API manages configurations and features for the entire coresight
@@ -260,6 +261,8 @@ static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc) { int err;
- spin_lock_init(&feat_desc->param_lock);
- /* add feature to any matching registered devices */ err = cscfg_add_feat_to_csdevs(feat_desc); if (err)
@@ -294,6 +297,24 @@ static int cscfg_load_config(struct cscfg_config_desc *cfg_desc) return err; } +/* get a feature descriptor by name */ +const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name) +{
- const struct cscfg_feature_desc *feat = NULL, *feat_item;
- mutex_lock(&cscfg_mutex);
- list_for_each_entry(feat_item, &cscfg_data.feat_list, item) {
if (strcmp(feat_item->name, name) == 0) {
feat = feat_item;
break;
}
- }
- mutex_unlock(&cscfg_mutex);
- return feat;
+}
/*
- External API function to load feature and config sets.
- Take a 0 terminated array of feature descriptors and/or configuration
@@ -316,6 +337,7 @@ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, feat_descs[i]->name); goto do_unlock; }
} }cscfg_configfs_add_feature(feat_descs[i]); i++;
@@ -330,6 +352,7 @@ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, cfg_descs[i]->name); goto do_unlock; }
} }cscfg_configfs_add_config(cfg_descs[i]); i++;
@@ -502,6 +525,7 @@ struct device *to_device_cscfg(void) /* Must have a release function or the kernel will complain on module unload */ void cscfg_dev_release(struct device *dev) {
- cscfg_configfs_release(cscfg_dev); kfree(cscfg_dev); cscfg_dev = NULL;
} @@ -530,6 +554,7 @@ int cscfg_create_device(void) cscfg_dev->cfg_data = &cscfg_data; err = device_register(dev);
- if (err) cscfg_dev_release(dev);
@@ -587,6 +612,10 @@ int __init cscfg_init(void) if (err) goto exit_drv_unregister;
- err = cscfg_configfs_init(cscfg_dev);
- if (err)
goto exit_dev_clear;
- INIT_LIST_HEAD(&cscfg_data.dev_list); INIT_LIST_HEAD(&cscfg_data.feat_list); INIT_LIST_HEAD(&cscfg_data.config_list);
@@ -595,6 +624,8 @@ int __init cscfg_init(void) dev_info(to_device_cscfg(), "CoreSight Configuration manager initialised"); return 0; +exit_dev_clear:
- cscfg_clear_device();
exit_drv_unregister: cscfg_driver_exit(); exit_bus_unregister: diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index e8f352599dd7..ce237a69677b 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -6,6 +6,7 @@ #ifndef CORESIGHT_SYSCFG_H #define CORESIGHT_SYSCFG_H +#include <linux/configfs.h> #include <linux/coresight.h> #include <linux/device.h> @@ -46,6 +47,7 @@ struct cscfg_csdev_register { int __init cscfg_init(void); void __exit cscfg_exit(void); int cscfg_preload(void); +const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name); /* syscfg external API */ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, @@ -64,10 +66,12 @@ void cscfg_unregister_csdev(struct coresight_device *csdev);
- @dev: The device.
- @cfg_data: A reference to the configuration and feature lists
*/
- @cfgfs_subsys: configfs subsystem used to manage configurations.
struct cscfg_device { struct device dev; struct cscfg_api_data *cfg_data;
- struct cscfg_fs_subsys *cfgfs_subsys;
}; /* basic device driver */ -- 2.17.1
Add in functionality to allow the user to update feature default parameter values from the configfs interface.
This updates all the device instances with the new values, removing the need to set all devices individually via sysfs.
Signed-off-by: Mike Leach mike.leach@linaro.org --- .../hwtracing/coresight/coresight-config.c | 36 ++++++++++++++++--- .../hwtracing/coresight/coresight-config.h | 1 + .../coresight/coresight-syscfg-configfs.c | 3 ++ .../hwtracing/coresight/coresight-syscfg.c | 15 ++++++++ .../hwtracing/coresight/coresight-syscfg.h | 1 + 5 files changed, 52 insertions(+), 4 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-config.c b/drivers/hwtracing/coresight/coresight-config.c index 04e7cb4ff769..7d30a415f2ff 100644 --- a/drivers/hwtracing/coresight/coresight-config.c +++ b/drivers/hwtracing/coresight/coresight-config.c @@ -96,6 +96,17 @@ static void cscfg_save_on_disable(struct cscfg_feature_csdev *feat, const bool f spin_unlock(feat->csdev_spinlock); }
+/* load default values into params */ +static void cscfg_set_param_defaults(struct cscfg_feature_csdev *feat) +{ + int i; + + spin_lock(&feat->desc->param_lock); + for (i = 0; i < feat->nr_params; i++) + feat->params[i].current_value = feat->desc->params[i].value; + spin_unlock(&feat->desc->param_lock); +} + /* default reset - restore default values, disable feature */ static void cscfg_reset_feat(struct cscfg_feature_csdev *feat) { @@ -111,10 +122,7 @@ static void cscfg_reset_feat(struct cscfg_feature_csdev *feat) * set the default values for all parameters and regs from the * relevant static descriptors. */ - spin_lock(&feat->desc->param_lock); - for (i = 0; i < feat->nr_params; i++) - feat->params[i].current_value = feat->desc->params[i].value; - spin_unlock(&feat->desc->param_lock); + cscfg_set_param_defaults(feat);
for (i = 0; i < feat->nr_regs; i++) { reg_desc = &feat->desc->regs[i]; @@ -131,6 +139,26 @@ static void cscfg_reset_feat(struct cscfg_feature_csdev *feat) spin_unlock(feat->csdev_spinlock); }
+/* update the parameters in a named feature from their defaults for the supplied device */ +void cscfg_csdev_set_param_defaults(struct coresight_device *csdev, const char *feat_name) +{ + struct cscfg_feature_csdev *feat; + + spin_lock(&csdev->cfg_lock); + if (list_empty(&csdev->feat_list)) { + spin_unlock(&csdev->cfg_lock); + return; + } + + list_for_each_entry(feat, &csdev->feat_list, node) { + if (!strcmp(feat_name, feat->desc->name)) { + cscfg_set_param_defaults(feat); + break; + } + } + spin_unlock(&csdev->cfg_lock); +} + void cscfg_set_def_ops(struct cscfg_feature_csdev *feat) { feat->ops.set_on_enable = cscfg_set_on_enable; diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 39fcac011aa0..1c6f0f903861 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -297,6 +297,7 @@ struct cscfg_csdev_feat_ops {
/* helper functions for feature manipulation */ void cscfg_set_def_ops(struct cscfg_feature_csdev *feat); +void cscfg_csdev_set_param_defaults(struct coresight_device *csdev, const char *feat_name);
/* enable / disable features or configs on a device */ int cscfg_csdev_set_enabled_feats(struct coresight_device *csdev); diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c index ff7ea678100a..1595c0c61db1 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c @@ -242,6 +242,9 @@ static ssize_t cscfg_param_value_store(struct config_item *item, param_item->param->value = val; spin_unlock(¶m_item->desc->param_lock);
+ /* push new value out to devices */ + cscfg_update_named_feat_csdevs(param_item->desc->name); + return size; } CONFIGFS_ATTR(cscfg_param_, value); diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 2cf67a038cc8..c42374342806 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -315,6 +315,21 @@ const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name) return feat; }
+/* + * Set all parameter defaults for named feature. + * Iterates through csdev list and updates param defaults on named feature. + */ +void cscfg_update_named_feat_csdevs(const char *feat_name) +{ + struct cscfg_csdev_register *curr_item; + + mutex_lock(&cscfg_mutex); + list_for_each_entry(curr_item, &cscfg_data.dev_list, item) { + cscfg_csdev_set_param_defaults(curr_item->csdev, feat_name); + } + mutex_unlock(&cscfg_mutex); +} + /* * External API function to load feature and config sets. * Take a 0 terminated array of feature descriptors and/or configuration diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index ce237a69677b..d07a0f11097f 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -48,6 +48,7 @@ int __init cscfg_init(void); void __exit cscfg_exit(void); int cscfg_preload(void); const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name); +void cscfg_update_named_feat_csdevs(const char *feat_name);
/* syscfg external API */ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs,
On Fri, Oct 30, 2020 at 05:56:54PM +0000, Mike Leach wrote:
Add in functionality to allow the user to update feature default parameter values from the configfs interface.
This updates all the device instances with the new values, removing the need to set all devices individually via sysfs.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-config.c | 36 ++++++++++++++++--- .../hwtracing/coresight/coresight-config.h | 1 + .../coresight/coresight-syscfg-configfs.c | 3 ++ .../hwtracing/coresight/coresight-syscfg.c | 15 ++++++++ .../hwtracing/coresight/coresight-syscfg.h | 1 + 5 files changed, 52 insertions(+), 4 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-config.c b/drivers/hwtracing/coresight/coresight-config.c index 04e7cb4ff769..7d30a415f2ff 100644 --- a/drivers/hwtracing/coresight/coresight-config.c +++ b/drivers/hwtracing/coresight/coresight-config.c @@ -96,6 +96,17 @@ static void cscfg_save_on_disable(struct cscfg_feature_csdev *feat, const bool f spin_unlock(feat->csdev_spinlock); } +/* load default values into params */ +static void cscfg_set_param_defaults(struct cscfg_feature_csdev *feat) +{
- int i;
- spin_lock(&feat->desc->param_lock);
- for (i = 0; i < feat->nr_params; i++)
feat->params[i].current_value = feat->desc->params[i].value;
- spin_unlock(&feat->desc->param_lock);
+}
/* default reset - restore default values, disable feature */ static void cscfg_reset_feat(struct cscfg_feature_csdev *feat) { @@ -111,10 +122,7 @@ static void cscfg_reset_feat(struct cscfg_feature_csdev *feat) * set the default values for all parameters and regs from the * relevant static descriptors. */
- spin_lock(&feat->desc->param_lock);
- for (i = 0; i < feat->nr_params; i++)
feat->params[i].current_value = feat->desc->params[i].value;
- spin_unlock(&feat->desc->param_lock);
- cscfg_set_param_defaults(feat);
for (i = 0; i < feat->nr_regs; i++) { reg_desc = &feat->desc->regs[i]; @@ -131,6 +139,26 @@ static void cscfg_reset_feat(struct cscfg_feature_csdev *feat) spin_unlock(feat->csdev_spinlock); } +/* update the parameters in a named feature from their defaults for the supplied device */ +void cscfg_csdev_set_param_defaults(struct coresight_device *csdev, const char *feat_name) +{
- struct cscfg_feature_csdev *feat;
- spin_lock(&csdev->cfg_lock);
- if (list_empty(&csdev->feat_list)) {
spin_unlock(&csdev->cfg_lock);
return;
- }
- list_for_each_entry(feat, &csdev->feat_list, node) {
if (!strcmp(feat_name, feat->desc->name)) {
cscfg_set_param_defaults(feat);
break;
}
- }
- spin_unlock(&csdev->cfg_lock);
+}
void cscfg_set_def_ops(struct cscfg_feature_csdev *feat) { feat->ops.set_on_enable = cscfg_set_on_enable; diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 39fcac011aa0..1c6f0f903861 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -297,6 +297,7 @@ struct cscfg_csdev_feat_ops { /* helper functions for feature manipulation */ void cscfg_set_def_ops(struct cscfg_feature_csdev *feat); +void cscfg_csdev_set_param_defaults(struct coresight_device *csdev, const char *feat_name); /* enable / disable features or configs on a device */ int cscfg_csdev_set_enabled_feats(struct coresight_device *csdev); diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c index ff7ea678100a..1595c0c61db1 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c @@ -242,6 +242,9 @@ static ssize_t cscfg_param_value_store(struct config_item *item, param_item->param->value = val; spin_unlock(¶m_item->desc->param_lock);
- /* push new value out to devices */
- cscfg_update_named_feat_csdevs(param_item->desc->name);
- return size;
} CONFIGFS_ATTR(cscfg_param_, value); diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 2cf67a038cc8..c42374342806 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -315,6 +315,21 @@ const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name) return feat; } +/*
- Set all parameter defaults for named feature.
- Iterates through csdev list and updates param defaults on named feature.
- */
+void cscfg_update_named_feat_csdevs(const char *feat_name) +{
- struct cscfg_csdev_register *curr_item;
- mutex_lock(&cscfg_mutex);
- list_for_each_entry(curr_item, &cscfg_data.dev_list, item) {
cscfg_csdev_set_param_defaults(curr_item->csdev, feat_name);
- }
- mutex_unlock(&cscfg_mutex);
This is what I was referring to when expressing my worries about the number of locks to manage. Here we have a mutex holding a spinlock holding another spinlock. It is a matter of time before we lockup the system. I think RCUs will be our only option but that will seriously impede readability.
I currently don't have anything better to suggest and as such will accept to move forward with the current situation. We may think of something better as this set continue to mature.
+}
/*
- External API function to load feature and config sets.
- Take a 0 terminated array of feature descriptors and/or configuration
diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index ce237a69677b..d07a0f11097f 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -48,6 +48,7 @@ int __init cscfg_init(void); void __exit cscfg_exit(void); int cscfg_preload(void); const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name); +void cscfg_update_named_feat_csdevs(const char *feat_name); /* syscfg external API */ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, -- 2.17.1
Hi Mathieu,
On Thu, 26 Nov 2020 at 17:17, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Fri, Oct 30, 2020 at 05:56:54PM +0000, Mike Leach wrote:
Add in functionality to allow the user to update feature default parameter values from the configfs interface.
This updates all the device instances with the new values, removing the need to set all devices individually via sysfs.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-config.c | 36 ++++++++++++++++--- .../hwtracing/coresight/coresight-config.h | 1 + .../coresight/coresight-syscfg-configfs.c | 3 ++ .../hwtracing/coresight/coresight-syscfg.c | 15 ++++++++ .../hwtracing/coresight/coresight-syscfg.h | 1 + 5 files changed, 52 insertions(+), 4 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-config.c b/drivers/hwtracing/coresight/coresight-config.c index 04e7cb4ff769..7d30a415f2ff 100644 --- a/drivers/hwtracing/coresight/coresight-config.c +++ b/drivers/hwtracing/coresight/coresight-config.c @@ -96,6 +96,17 @@ static void cscfg_save_on_disable(struct cscfg_feature_csdev *feat, const bool f spin_unlock(feat->csdev_spinlock); }
+/* load default values into params */ +static void cscfg_set_param_defaults(struct cscfg_feature_csdev *feat) +{
int i;
spin_lock(&feat->desc->param_lock);
for (i = 0; i < feat->nr_params; i++)
feat->params[i].current_value = feat->desc->params[i].value;
spin_unlock(&feat->desc->param_lock);
+}
/* default reset - restore default values, disable feature */ static void cscfg_reset_feat(struct cscfg_feature_csdev *feat) { @@ -111,10 +122,7 @@ static void cscfg_reset_feat(struct cscfg_feature_csdev *feat) * set the default values for all parameters and regs from the * relevant static descriptors. */
spin_lock(&feat->desc->param_lock);
for (i = 0; i < feat->nr_params; i++)
feat->params[i].current_value = feat->desc->params[i].value;
spin_unlock(&feat->desc->param_lock);
cscfg_set_param_defaults(feat); for (i = 0; i < feat->nr_regs; i++) { reg_desc = &feat->desc->regs[i];
@@ -131,6 +139,26 @@ static void cscfg_reset_feat(struct cscfg_feature_csdev *feat) spin_unlock(feat->csdev_spinlock); }
+/* update the parameters in a named feature from their defaults for the supplied device */ +void cscfg_csdev_set_param_defaults(struct coresight_device *csdev, const char *feat_name) +{
struct cscfg_feature_csdev *feat;
spin_lock(&csdev->cfg_lock);
if (list_empty(&csdev->feat_list)) {
spin_unlock(&csdev->cfg_lock);
return;
}
list_for_each_entry(feat, &csdev->feat_list, node) {
if (!strcmp(feat_name, feat->desc->name)) {
cscfg_set_param_defaults(feat);
break;
}
}
spin_unlock(&csdev->cfg_lock);
+}
void cscfg_set_def_ops(struct cscfg_feature_csdev *feat) { feat->ops.set_on_enable = cscfg_set_on_enable; diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 39fcac011aa0..1c6f0f903861 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -297,6 +297,7 @@ struct cscfg_csdev_feat_ops {
/* helper functions for feature manipulation */ void cscfg_set_def_ops(struct cscfg_feature_csdev *feat); +void cscfg_csdev_set_param_defaults(struct coresight_device *csdev, const char *feat_name);
/* enable / disable features or configs on a device */ int cscfg_csdev_set_enabled_feats(struct coresight_device *csdev); diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c index ff7ea678100a..1595c0c61db1 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c @@ -242,6 +242,9 @@ static ssize_t cscfg_param_value_store(struct config_item *item, param_item->param->value = val; spin_unlock(¶m_item->desc->param_lock);
/* push new value out to devices */
cscfg_update_named_feat_csdevs(param_item->desc->name);
return size;
} CONFIGFS_ATTR(cscfg_param_, value); diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 2cf67a038cc8..c42374342806 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -315,6 +315,21 @@ const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name) return feat; }
+/*
- Set all parameter defaults for named feature.
- Iterates through csdev list and updates param defaults on named feature.
- */
+void cscfg_update_named_feat_csdevs(const char *feat_name) +{
struct cscfg_csdev_register *curr_item;
mutex_lock(&cscfg_mutex);
list_for_each_entry(curr_item, &cscfg_data.dev_list, item) {
cscfg_csdev_set_param_defaults(curr_item->csdev, feat_name);
}
mutex_unlock(&cscfg_mutex);
This is what I was referring to when expressing my worries about the number of locks to manage. Here we have a mutex holding a spinlock holding another spinlock. It is a matter of time before we lockup the system. I think RCUs will be our only option but that will seriously impede readability.
I currently don't have anything better to suggest and as such will accept to move forward with the current situation. We may think of something better as this set continue to mature.
yes - I was concerned about this too. I have been working on a follow up set to allow dynamic loading of configs - which necessitated protecting loaded configs in use from unload. This resulted in the use of a reference counting get / put paradigm for config descriptors.
This method has been integrated into the next version of this patchset, and all the locks / protection code re-configured - dropping a couple of the locks along the way.
Regards
Mike
+}
/*
- External API function to load feature and config sets.
- Take a 0 terminated array of feature descriptors and/or configuration
diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index ce237a69677b..d07a0f11097f 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -48,6 +48,7 @@ int __init cscfg_init(void); void __exit cscfg_exit(void); int cscfg_preload(void); const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name); +void cscfg_update_named_feat_csdevs(const char *feat_name);
/* syscfg external API */ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, -- 2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
Adds documentation for the CoreSight System configuration manager.
Signed-off-by: Mike Leach mike.leach@linaro.org --- .../trace/coresight/coresight-config.rst | 230 ++++++++++++++++++ Documentation/trace/coresight/coresight.rst | 16 ++ 2 files changed, 246 insertions(+) create mode 100644 Documentation/trace/coresight/coresight-config.rst
diff --git a/Documentation/trace/coresight/coresight-config.rst b/Documentation/trace/coresight/coresight-config.rst new file mode 100644 index 000000000000..8afcf18c090c --- /dev/null +++ b/Documentation/trace/coresight/coresight-config.rst @@ -0,0 +1,230 @@ +.. SPDX-License-Identifier: GPL-2.0 + +====================================== +CoreSight System Configuration Manager +====================================== + + :Author: Mike Leach mike.leach@linaro.org + :Date: October 2020 + +Introduction +============ + +The CoreSight System Configuration manager is an API that allows the +programming of the CoreSight system with pre-defined configurations that +can then be easily enabled from sysfs or perf. + +Many CoreSight components can be programmed in complex ways - especially ETMs. +In addition, components can interact across the CoreSight system, often via +the cross trigger components such as CTI and CTM. These system settings can +be defined and enabled as named configurations. + + +Basic Concepts +============== + +This section introduces the basic concepts of a complex system configuration. + + +Features +-------- + +A feature is a named set of programming for a CoreSight device. The programming +is device dependent, and can be defined in terms of absolute register values, +resource usage and parameter values. + +The feature is defined using a descriptor. This descriptor is used to load onto +a matching device, either when the feature is loaded into the system, or when the +device is registered with the configuration manager. + +The load process involves interpreting the descriptor into a the set of register +accesses in the driver - the resource usage and parameter descriptions +translated into appropriate register accesses. This interpretation makes it easy +and efficient for the feature to be programmed onto the device when required. + +The feature will not be active on the device until the feature is enabled, and +the device itself is enabled. When the device is enabled then enabled features +will be programmed into the device hardware. + +A feature can be enabled either as part of a configuration being enabled on the +system, or individually on a device instance using the configfs API. + + +Parameter Value +~~~~~~~~~~~~~~~ + +A parameter value is a named value that may be set by the user prior to the +feature being enabled that can adjust the behaviour of the operation programmed +by the feature. + +For example, this could be a count value in a programmed operation that repeats +at a given rate. When the feature is enabled then the current value of the +parameter is used in programming the device. + +The feature descriptor defines a default value for a parameter, which is used +if the user does not supply a new value. + +Users can update parameter values using the configfs API for the CoreSight +system - which is described below. + +The current value of the parameter is loaded into the device when the feature +is enabled on that device. + + +Configurations +-------------- + +A configuration defines a set of features that are to be used in a trace +session where the configuration is selected. For any trace session only one +configuration may be selected. + +The features defined may be on any type of device that is registered +to support system configuration. A configuration may select features to be +enabled on a class of devices - i.e. any ETMv4, or specific devices, e.g. a +specific CTI on the system. + +As with the feature, a descriptor is used to define the configuration. +This will define the features that must be enabled as part of the configuration +as well as any preset values that can be used to override default parameter +values. + + +Preset Values +~~~~~~~~~~~~~ + +Preset values are easily selectable sets of parameter values for the features +that the configuration uses. The number of values in a single preset set, equals +the sum of parameter values in the features used by the configuration. + +e.g. a configuration consists of 3 features, one has 2 parameters, one has +a single parameter, and another has no parameters. A single preset set will +therefore have 3 values. + +Presets are optionally defined by the configuration, up to 15 can be defined. +If no preset is selected, then the parameter values defined in the feature +are used as normal. + + +Virtual Device +-------------- + +The CoreSight System Configuration manager also includes a virtual CoreSight +device. This provides the system with access to kernel objects and device +management to own elements such as the sysfs entries used to expose the +configurations into the cs_etm event in perf. + +This device 'system_cfg' appears on a custom bus - 'coresight-config' - +rather than the normal 'coresight' bus to avoid complications when the +coresight system is searching for real devices on the bus. + + +Viewing Configurations and Features +=================================== + +The set of configurations and features that are currently loaded into the +system can be viewed using the configfs API. + +Mount configfs as normal and the 'coresight-syscfg' subsystem will appear:: + + $ ls /config + coresight-syscfg stp-policy + +This has two sub-directories:: + + $ cd coresight-syscfg/ + $ ls + configurations features + +The system has the configuration 'autofdo' built in. It may be examined as +follows:: + + $ cd configurations/ + $ ls + autofdo + $ cd autofdo/ + $ ls + description nr_presets preset_values refs + $ cat description + Setup ETMs with strobing for autofdo + $ cat refs + references 1 features:- + strobing + $ cat nr_presets + 2 + $ cat preset_values + 2 presets, 2 parameters per preset + preset[1]: strobing.window = 0x2710 strobing.period = 0x1388 + preset[2]: strobing.window = 0x1388 strobing.period = 0x1388 + +The features referenced by the configuration can be examined in the features +directory:: + + $ cd ../../features/strobing/ + $ ls + description matches nr_params params + $ cat description + Generate periodic trace capture windows. + parameter 'window': a number of CPU cycles (W) + parameter 'period': trace enabled for W cycles every period x W cycles + $ cat matches + SRC_ETMV4 + $ cat nr_params + 2 + +Move to the params directory to examine and adjust parameters:: + + cd params + $ ls + period window + $ cd period + $ ls + value + $ cat value + 0x2710 + # echo 15000 > value + # cat value + 0x3a98 + +Parameters adjusted in this way are reflected in all device instances that have +loaded the feature. + + +Using Configurations in perf +============================ + +The configurations loaded into the CoreSight configuration management are +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 + +Key directories here are 'configurations' - which lists the loaded +configurations, and 'events' - a generic perf directory which allows +selection on the perf command line.:: + + $ 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:: + + $ ls events/ + autofdo + $ cat events/autofdo + configid=0xa7c3dddd + +The 'autofdo' configuration may be selected on the perf command line:: + + $ perf record -e cs_etm/autofdo/u --per-thread <application> + +A preset to override the current parameter values can also be selected:: + + $ perf record -e cs_etm/autofdo,preset=1/u --per-thread <application> + +When configurations are selected in this way, then the trace sink used is +automatically selected. diff --git a/Documentation/trace/coresight/coresight.rst b/Documentation/trace/coresight/coresight.rst index 0b73acb44efa..0122d9bebf35 100644 --- a/Documentation/trace/coresight/coresight.rst +++ b/Documentation/trace/coresight/coresight.rst @@ -587,6 +587,20 @@ A separate documentation file is provided to explain the use of these devices. (:doc:`coresight-ect`) [#fourth]_.
+CoreSight System Configuration +------------------------------ + +CoreSight components can be complex devices with many programming options. +Furthermore, components can be programmed to interact with each other across the +complete system. + +A CoreSight System Configuration manager is provided to allow these complex programming +configurations to be selected and used easily from perf and sysfs. + +See the separate document for further information. +(:doc:`coresight-config`) [#fifth]_. + + .. [#first] Documentation/ABI/testing/sysfs-bus-coresight-devices-stm
.. [#second] Documentation/trace/stm.rst @@ -594,3 +608,5 @@ A separate documentation file is provided to explain the use of these devices. .. [#third] https://github.com/Linaro/perf-opencsd
.. [#fourth] Documentation/trace/coresight/coresight-ect.rst + +.. [#fifth] Documentation/trace/coresight/coresight-config.rst
On Fri, Oct 30, 2020 at 05:56:55PM +0000, Mike Leach wrote:
Adds documentation for the CoreSight System configuration manager.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../trace/coresight/coresight-config.rst | 230 ++++++++++++++++++ Documentation/trace/coresight/coresight.rst | 16 ++ 2 files changed, 246 insertions(+) create mode 100644 Documentation/trace/coresight/coresight-config.rst
diff --git a/Documentation/trace/coresight/coresight-config.rst b/Documentation/trace/coresight/coresight-config.rst new file mode 100644 index 000000000000..8afcf18c090c --- /dev/null +++ b/Documentation/trace/coresight/coresight-config.rst @@ -0,0 +1,230 @@ +.. SPDX-License-Identifier: GPL-2.0
+====================================== +CoreSight System Configuration Manager +======================================
- :Author: Mike Leach mike.leach@linaro.org
- :Date: October 2020
+Introduction +============
+The CoreSight System Configuration manager is an API that allows the +programming of the CoreSight system with pre-defined configurations that +can then be easily enabled from sysfs or perf.
+Many CoreSight components can be programmed in complex ways - especially ETMs. +In addition, components can interact across the CoreSight system, often via +the cross trigger components such as CTI and CTM. These system settings can +be defined and enabled as named configurations.
+Basic Concepts +==============
+This section introduces the basic concepts of a complex system configuration.
+Features +--------
+A feature is a named set of programming for a CoreSight device. The programming +is device dependent, and can be defined in terms of absolute register values, +resource usage and parameter values.
+The feature is defined using a descriptor. This descriptor is used to load onto +a matching device, either when the feature is loaded into the system, or when the +device is registered with the configuration manager.
In the above paragraph I would explicitly write "coresight device" when referring to a device. That way there is no doubt as to what is happening.
+The load process involves interpreting the descriptor into a the set of register
s/into a the set/into a set/
+accesses in the driver - the resource usage and parameter descriptions +translated into appropriate register accesses. This interpretation makes it easy +and efficient for the feature to be programmed onto the device when required.
+The feature will not be active on the device until the feature is enabled, and +the device itself is enabled. When the device is enabled then enabled features +will be programmed into the device hardware.
If I understand correctly the above paragraph is for the sysfs and configfs interfaces. From perf enabling feature and devices doesn't apply.
+A feature can be enabled either as part of a configuration being enabled on the +system, or individually on a device instance using the configfs API.
+Parameter Value +~~~~~~~~~~~~~~~
+A parameter value is a named value that may be set by the user prior to the +feature being enabled that can adjust the behaviour of the operation programmed +by the feature.
+For example, this could be a count value in a programmed operation that repeats +at a given rate. When the feature is enabled then the current value of the +parameter is used in programming the device.
+The feature descriptor defines a default value for a parameter, which is used +if the user does not supply a new value.
+Users can update parameter values using the configfs API for the CoreSight +system - which is described below.
+The current value of the parameter is loaded into the device when the feature +is enabled on that device.
+Configurations +--------------
+A configuration defines a set of features that are to be used in a trace +session where the configuration is selected. For any trace session only one +configuration may be selected.
+The features defined may be on any type of device that is registered +to support system configuration. A configuration may select features to be +enabled on a class of devices - i.e. any ETMv4, or specific devices, e.g. a +specific CTI on the system.
+As with the feature, a descriptor is used to define the configuration. +This will define the features that must be enabled as part of the configuration +as well as any preset values that can be used to override default parameter +values.
+Preset Values +~~~~~~~~~~~~~
+Preset values are easily selectable sets of parameter values for the features +that the configuration uses. The number of values in a single preset set, equals +the sum of parameter values in the features used by the configuration.
+e.g. a configuration consists of 3 features, one has 2 parameters, one has +a single parameter, and another has no parameters. A single preset set will +therefore have 3 values.
+Presets are optionally defined by the configuration, up to 15 can be defined. +If no preset is selected, then the parameter values defined in the feature +are used as normal.
+Virtual Device +--------------
+The CoreSight System Configuration manager also includes a virtual CoreSight +device. This provides the system with access to kernel objects and device +management to own elements such as the sysfs entries used to expose the +configurations into the cs_etm event in perf.
+This device 'system_cfg' appears on a custom bus - 'coresight-config' - +rather than the normal 'coresight' bus to avoid complications when the +coresight system is searching for real devices on the bus.
+Viewing Configurations and Features +===================================
+The set of configurations and features that are currently loaded into the +system can be viewed using the configfs API.
+Mount configfs as normal and the 'coresight-syscfg' subsystem will appear::
- $ ls /config
- coresight-syscfg stp-policy
+This has two sub-directories::
- $ cd coresight-syscfg/
- $ ls
- configurations features
+The system has the configuration 'autofdo' built in. It may be examined as +follows::
- $ cd configurations/
- $ ls
- autofdo
- $ cd autofdo/
- $ ls
- description nr_presets preset_values refs
- $ cat description
- Setup ETMs with strobing for autofdo
- $ cat refs
- references 1 features:-
- strobing
- $ cat nr_presets
- 2
- $ cat preset_values
- 2 presets, 2 parameters per preset
- preset[1]: strobing.window = 0x2710 strobing.period = 0x1388
- preset[2]: strobing.window = 0x1388 strobing.period = 0x1388
+The features referenced by the configuration can be examined in the features +directory::
- $ cd ../../features/strobing/
- $ ls
- description matches nr_params params
- $ cat description
- Generate periodic trace capture windows.
- parameter 'window': a number of CPU cycles (W)
- parameter 'period': trace enabled for W cycles every period x W cycles
- $ cat matches
- SRC_ETMV4
- $ cat nr_params
- 2
+Move to the params directory to examine and adjust parameters::
- cd params
- $ ls
- period window
- $ cd period
- $ ls
- value
- $ cat value
- 0x2710
- # echo 15000 > value
- # cat value
- 0x3a98
+Parameters adjusted in this way are reflected in all device instances that have +loaded the feature.
+Using Configurations in perf +============================
+The configurations loaded into the CoreSight configuration management are +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
+Key directories here are 'configurations' - which lists the loaded +configurations, and 'events' - a generic perf directory which allows +selection on the perf command line.::
- $ 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::
- $ ls events/
- autofdo
- $ cat events/autofdo
- configid=0xa7c3dddd
+The 'autofdo' configuration may be selected on the perf command line::
- $ perf record -e cs_etm/autofdo/u --per-thread <application>
+A preset to override the current parameter values can also be selected::
- $ perf record -e cs_etm/autofdo,preset=1/u --per-thread <application>
+When configurations are selected in this way, then the trace sink used is +automatically selected. diff --git a/Documentation/trace/coresight/coresight.rst b/Documentation/trace/coresight/coresight.rst index 0b73acb44efa..0122d9bebf35 100644 --- a/Documentation/trace/coresight/coresight.rst +++ b/Documentation/trace/coresight/coresight.rst @@ -587,6 +587,20 @@ A separate documentation file is provided to explain the use of these devices. (:doc:`coresight-ect`) [#fourth]_. +CoreSight System Configuration +------------------------------
+CoreSight components can be complex devices with many programming options. +Furthermore, components can be programmed to interact with each other across the +complete system.
+A CoreSight System Configuration manager is provided to allow these complex programming +configurations to be selected and used easily from perf and sysfs.
+See the separate document for further information. +(:doc:`coresight-config`) [#fifth]_.
.. [#first] Documentation/ABI/testing/sysfs-bus-coresight-devices-stm .. [#second] Documentation/trace/stm.rst @@ -594,3 +608,5 @@ A separate documentation file is provided to explain the use of these devices. .. [#third] https://github.com/Linaro/perf-opencsd .. [#fourth] Documentation/trace/coresight/coresight-ect.rst
+.. [#fifth] Documentation/trace/coresight/coresight-config.rst
2.17.1
Hi Mathieu,
On Thu, 26 Nov 2020 at 17:52, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Fri, Oct 30, 2020 at 05:56:55PM +0000, Mike Leach wrote:
Adds documentation for the CoreSight System configuration manager.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../trace/coresight/coresight-config.rst | 230 ++++++++++++++++++ Documentation/trace/coresight/coresight.rst | 16 ++ 2 files changed, 246 insertions(+) create mode 100644 Documentation/trace/coresight/coresight-config.rst
diff --git a/Documentation/trace/coresight/coresight-config.rst b/Documentation/trace/coresight/coresight-config.rst new file mode 100644 index 000000000000..8afcf18c090c --- /dev/null +++ b/Documentation/trace/coresight/coresight-config.rst @@ -0,0 +1,230 @@ +.. SPDX-License-Identifier: GPL-2.0
+====================================== +CoreSight System Configuration Manager +======================================
- :Author: Mike Leach mike.leach@linaro.org
- :Date: October 2020
+Introduction +============
+The CoreSight System Configuration manager is an API that allows the +programming of the CoreSight system with pre-defined configurations that +can then be easily enabled from sysfs or perf.
+Many CoreSight components can be programmed in complex ways - especially ETMs. +In addition, components can interact across the CoreSight system, often via +the cross trigger components such as CTI and CTM. These system settings can +be defined and enabled as named configurations.
+Basic Concepts +==============
+This section introduces the basic concepts of a complex system configuration.
+Features +--------
+A feature is a named set of programming for a CoreSight device. The programming +is device dependent, and can be defined in terms of absolute register values, +resource usage and parameter values.
+The feature is defined using a descriptor. This descriptor is used to load onto +a matching device, either when the feature is loaded into the system, or when the +device is registered with the configuration manager.
In the above paragraph I would explicitly write "coresight device" when referring to a device. That way there is no doubt as to what is happening.
+The load process involves interpreting the descriptor into a the set of register
s/into a the set/into a set/
+accesses in the driver - the resource usage and parameter descriptions +translated into appropriate register accesses. This interpretation makes it easy +and efficient for the feature to be programmed onto the device when required.
+The feature will not be active on the device until the feature is enabled, and +the device itself is enabled. When the device is enabled then enabled features +will be programmed into the device hardware.
If I understand correctly the above paragraph is for the sysfs and configfs interfaces. From perf enabling feature and devices doesn't apply.
No - this also applies to perf. The principle is that perf will enable a config. But it will only be programmed on to the devices that the perf event is enabled on.
Thanks
Mike
+A feature can be enabled either as part of a configuration being enabled on the +system, or individually on a device instance using the configfs API.
+Parameter Value +~~~~~~~~~~~~~~~
+A parameter value is a named value that may be set by the user prior to the +feature being enabled that can adjust the behaviour of the operation programmed +by the feature.
+For example, this could be a count value in a programmed operation that repeats +at a given rate. When the feature is enabled then the current value of the +parameter is used in programming the device.
+The feature descriptor defines a default value for a parameter, which is used +if the user does not supply a new value.
+Users can update parameter values using the configfs API for the CoreSight +system - which is described below.
+The current value of the parameter is loaded into the device when the feature +is enabled on that device.
+Configurations +--------------
+A configuration defines a set of features that are to be used in a trace +session where the configuration is selected. For any trace session only one +configuration may be selected.
+The features defined may be on any type of device that is registered +to support system configuration. A configuration may select features to be +enabled on a class of devices - i.e. any ETMv4, or specific devices, e.g. a +specific CTI on the system.
+As with the feature, a descriptor is used to define the configuration. +This will define the features that must be enabled as part of the configuration +as well as any preset values that can be used to override default parameter +values.
+Preset Values +~~~~~~~~~~~~~
+Preset values are easily selectable sets of parameter values for the features +that the configuration uses. The number of values in a single preset set, equals +the sum of parameter values in the features used by the configuration.
+e.g. a configuration consists of 3 features, one has 2 parameters, one has +a single parameter, and another has no parameters. A single preset set will +therefore have 3 values.
+Presets are optionally defined by the configuration, up to 15 can be defined. +If no preset is selected, then the parameter values defined in the feature +are used as normal.
+Virtual Device +--------------
+The CoreSight System Configuration manager also includes a virtual CoreSight +device. This provides the system with access to kernel objects and device +management to own elements such as the sysfs entries used to expose the +configurations into the cs_etm event in perf.
+This device 'system_cfg' appears on a custom bus - 'coresight-config' - +rather than the normal 'coresight' bus to avoid complications when the +coresight system is searching for real devices on the bus.
+Viewing Configurations and Features +===================================
+The set of configurations and features that are currently loaded into the +system can be viewed using the configfs API.
+Mount configfs as normal and the 'coresight-syscfg' subsystem will appear::
- $ ls /config
- coresight-syscfg stp-policy
+This has two sub-directories::
- $ cd coresight-syscfg/
- $ ls
- configurations features
+The system has the configuration 'autofdo' built in. It may be examined as +follows::
- $ cd configurations/
- $ ls
- autofdo
- $ cd autofdo/
- $ ls
- description nr_presets preset_values refs
- $ cat description
- Setup ETMs with strobing for autofdo
- $ cat refs
- references 1 features:-
- strobing
- $ cat nr_presets
- 2
- $ cat preset_values
- 2 presets, 2 parameters per preset
- preset[1]: strobing.window = 0x2710 strobing.period = 0x1388
- preset[2]: strobing.window = 0x1388 strobing.period = 0x1388
+The features referenced by the configuration can be examined in the features +directory::
- $ cd ../../features/strobing/
- $ ls
- description matches nr_params params
- $ cat description
- Generate periodic trace capture windows.
- parameter 'window': a number of CPU cycles (W)
- parameter 'period': trace enabled for W cycles every period x W cycles
- $ cat matches
- SRC_ETMV4
- $ cat nr_params
- 2
+Move to the params directory to examine and adjust parameters::
- cd params
- $ ls
- period window
- $ cd period
- $ ls
- value
- $ cat value
- 0x2710
- # echo 15000 > value
- # cat value
- 0x3a98
+Parameters adjusted in this way are reflected in all device instances that have +loaded the feature.
+Using Configurations in perf +============================
+The configurations loaded into the CoreSight configuration management are +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
+Key directories here are 'configurations' - which lists the loaded +configurations, and 'events' - a generic perf directory which allows +selection on the perf command line.::
- $ 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::
- $ ls events/
- autofdo
- $ cat events/autofdo
- configid=0xa7c3dddd
+The 'autofdo' configuration may be selected on the perf command line::
- $ perf record -e cs_etm/autofdo/u --per-thread <application>
+A preset to override the current parameter values can also be selected::
- $ perf record -e cs_etm/autofdo,preset=1/u --per-thread <application>
+When configurations are selected in this way, then the trace sink used is +automatically selected. diff --git a/Documentation/trace/coresight/coresight.rst b/Documentation/trace/coresight/coresight.rst index 0b73acb44efa..0122d9bebf35 100644 --- a/Documentation/trace/coresight/coresight.rst +++ b/Documentation/trace/coresight/coresight.rst @@ -587,6 +587,20 @@ A separate documentation file is provided to explain the use of these devices. (:doc:`coresight-ect`) [#fourth]_.
+CoreSight System Configuration +------------------------------
+CoreSight components can be complex devices with many programming options. +Furthermore, components can be programmed to interact with each other across the +complete system.
+A CoreSight System Configuration manager is provided to allow these complex programming +configurations to be selected and used easily from perf and sysfs.
+See the separate document for further information. +(:doc:`coresight-config`) [#fifth]_.
.. [#first] Documentation/ABI/testing/sysfs-bus-coresight-devices-stm
.. [#second] Documentation/trace/stm.rst @@ -594,3 +608,5 @@ A separate documentation file is provided to explain the use of these devices. .. [#third] https://github.com/Linaro/perf-opencsd
.. [#fourth] Documentation/trace/coresight/coresight-ect.rst
+.. [#fifth] Documentation/trace/coresight/coresight-config.rst
2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
Hi Mike,
On Fri, Oct 30, 2020 at 05:56:46PM +0000, Mike Leach wrote:
This patchset introduces initial concepts in CoreSight complex system configuration support.
Configurations consist of 2 elements:-
- Features - programming combinations for devices, applied to a class of
device on the system (all ETMv4), or individual devices. 2) Configurations - a set of programmed features used when the named configuration is selected.
Features and configurations are declared as a data table, a set of register, resource and parameter requirements. Features and configurations are loaded into the system by the virtual cs_syscfg device. This then matches features to any registered devices and loads the feature into them.
Individual device classes that support feature and configuration register with cs_syscfg.
Once loaded a configuration can be enabled for a specific trace run. Configurations are registered with the perf cs_etm event as entries in cs_etm/cs_config. These can be selected on the perf command line as follows:-
perf record -e cs_etm/<config_name>/ ...
This patch set has one pre-loaded configuration and feature. A named "strobing" feature is provided for ETMv4. A named "autofdo" configuration is provided. This configuration enables strobing on any ETM in used.
Thus the command: perf record -e cs_etm/autofdo/ ...
will trace the supplied application while enabling the "autofdo" configuation on each ETM as it is enabled by perf. This in turn will enable strobing for the ETM - with default parameters. Parameters can be adjusted using configfs.
The sink used in the trace run will be automatically selected.
A configuation can supply up to 15 of preset parameter values, which will subsitute in parameter values for any feature used in the configuration.
Selection of preset values as follows perf record -e cs_etm/autofdo,preset=1/ ...
(valid presets 1-N, where N is the number supplied in the configuration, not exceeding 15. preset=0 is the same as not selecting a preset.)
Applies to coresight/next (5.10-rc1 base)
I am done reviewing this third revision. I commented on a fair amount of things but that isn't unusual with this much code, especially when it is new code that doesn't have a precedent.
As I stated before I think the general architecture of the feature is sound. The concepts of XYZ_desc and XYZ_csdev have now sunk in and I quite like it. It will be really good when the naming convention is straighten out.
I spent a long time thinking about creating configuration and features on the fly from configfs. It is definitely not something that needs to be part of this set, nor have to be implemented any time soon, but is this something that is on your radar?
Lastly the "RFC" should be dropped for the fourth iteration, we are way passed that point now.
Thanks, Mathieu
Changes since v2:
- Added documentation file.
- Altered cs_syscfg driver to no longer be coresight_device based, and moved
to its own custom bus to remove it from the main coresight bus. (Mathieu) 3) Added configfs support to inspect and control loaded configurations and features. Allows listing of preset values (Yabin Cui) 4) Dropped sysfs support for adjusting feature parameters on the per device basis, in favour of a single point adjustment in configfs that is pushed to all device instances. 5) Altered how the config and preset command line options are handled in perf and the drivers. (Mathieu and Suzuki). 6) Fixes for various issues and technical points (Mathieu, Yabin)
Changes since v1:
- Moved preloaded configurations and features out of individual drivers.
- Added cs_syscfg driver to manage configurations and features. Individual
drivers register with cs_syscfg indicating support for config, and provide matching information that the system uses to load features into the drivers. This allows individual drivers to be updated on an as needed basis - and removes the need to consider devices that cannot benefit from configuration - static replicators, funnels, tpiu. 3) Added perf selection of configuarations. 4) Rebased onto the coresight module loading set.
To follow in future revisions / sets:- a) load of additional config and features by loadable module. b) load of additional config and features by configfs c) enhanced resource management for ETMv4 and checking features have sufficient resources to be enabled. d) ECT and CTI support for configuration and features.
Mike Leach (9): coresight: syscfg: Initial coresight system configuration coresight: syscfg: Add registration and feature loading for cs devices coresight: config: Add configuration and feature generic functions coresight: etm-perf: update to handle configuration selection coresight: etm4x: Add complex configuration handlers to etmv4 coresight: config: Add preloaded configurations coresight: syscfg: Add initial configfs support. coresight: syscfg: Allow update of feature params from configfs coresight: docs: Add documentation for CoreSight config.
.../trace/coresight/coresight-config.rst | 230 ++++++ Documentation/trace/coresight/coresight.rst | 16 + drivers/hwtracing/coresight/Makefile | 6 +- .../coresight/coresight-cfg-preload.c | 160 +++++ .../hwtracing/coresight/coresight-config.c | 392 +++++++++++ .../hwtracing/coresight/coresight-config.h | 311 +++++++++ drivers/hwtracing/coresight/coresight-core.c | 18 +- .../hwtracing/coresight/coresight-etm-perf.c | 166 ++++- .../hwtracing/coresight/coresight-etm-perf.h | 10 +- .../hwtracing/coresight/coresight-etm4x-cfg.c | 181 +++++ .../hwtracing/coresight/coresight-etm4x-cfg.h | 29 + .../coresight/coresight-etm4x-core.c | 36 +- .../coresight/coresight-etm4x-sysfs.c | 3 + .../coresight/coresight-syscfg-configfs.c | 421 +++++++++++ .../coresight/coresight-syscfg-configfs.h | 47 ++ .../hwtracing/coresight/coresight-syscfg.c | 656 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 83 +++ include/linux/coresight.h | 7 + 18 files changed, 2743 insertions(+), 29 deletions(-) create mode 100644 Documentation/trace/coresight/coresight-config.rst create mode 100644 drivers/hwtracing/coresight/coresight-cfg-preload.c create mode 100644 drivers/hwtracing/coresight/coresight-config.c create mode 100644 drivers/hwtracing/coresight/coresight-config.h create mode 100644 drivers/hwtracing/coresight/coresight-etm4x-cfg.c create mode 100644 drivers/hwtracing/coresight/coresight-etm4x-cfg.h create mode 100644 drivers/hwtracing/coresight/coresight-syscfg-configfs.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg-configfs.h create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.h
-- 2.17.1
Hi MAthieu,
Thanks for the review as ever. Sorry its taken me a bit of time to respond, but there has been a bit of reworking to do.
I certainly agree with the _desc / _csdev convention, and the follow up set should address that. The locking is also reconfigured as mentioned - so that it is simpler.
The general rules have been tightened. I was trying to allow features to be enabled independently of configurations when driving the system from configfs / sysfs rather than perf. But in the end there is little value in that approach.
As mentioned I have been working on follow up patches - which should be able to be split into smaller changesets. One is the dynamic loading of configurations, which will be either by loadable module, or configfs. The latter will allow the user to mkdir in the configs directory, and then load a binary blob via a "load" file. I do not believe that it is practicable to define an entire set of features with registers and configs via configfs - given that it is relatively inflexible in terms of adding files dynamically from a kernel perspective.
That said, it may be possible later to add in a way to defne a configuration via configfs using previously defined named features only.
Regards
Mike
On Thu, 26 Nov 2020 at 18:52, Mathieu Poirier mathieu.poirier@linaro.org wrote:
Hi Mike,
On Fri, Oct 30, 2020 at 05:56:46PM +0000, Mike Leach wrote:
This patchset introduces initial concepts in CoreSight complex system configuration support.
Configurations consist of 2 elements:-
- Features - programming combinations for devices, applied to a class of
device on the system (all ETMv4), or individual devices. 2) Configurations - a set of programmed features used when the named configuration is selected.
Features and configurations are declared as a data table, a set of register, resource and parameter requirements. Features and configurations are loaded into the system by the virtual cs_syscfg device. This then matches features to any registered devices and loads the feature into them.
Individual device classes that support feature and configuration register with cs_syscfg.
Once loaded a configuration can be enabled for a specific trace run. Configurations are registered with the perf cs_etm event as entries in cs_etm/cs_config. These can be selected on the perf command line as follows:-
perf record -e cs_etm/<config_name>/ ...
This patch set has one pre-loaded configuration and feature. A named "strobing" feature is provided for ETMv4. A named "autofdo" configuration is provided. This configuration enables strobing on any ETM in used.
Thus the command: perf record -e cs_etm/autofdo/ ...
will trace the supplied application while enabling the "autofdo" configuation on each ETM as it is enabled by perf. This in turn will enable strobing for the ETM - with default parameters. Parameters can be adjusted using configfs.
The sink used in the trace run will be automatically selected.
A configuation can supply up to 15 of preset parameter values, which will subsitute in parameter values for any feature used in the configuration.
Selection of preset values as follows perf record -e cs_etm/autofdo,preset=1/ ...
(valid presets 1-N, where N is the number supplied in the configuration, not exceeding 15. preset=0 is the same as not selecting a preset.)
Applies to coresight/next (5.10-rc1 base)
I am done reviewing this third revision. I commented on a fair amount of things but that isn't unusual with this much code, especially when it is new code that doesn't have a precedent.
As I stated before I think the general architecture of the feature is sound. The concepts of XYZ_desc and XYZ_csdev have now sunk in and I quite like it. It will be really good when the naming convention is straighten out.
I spent a long time thinking about creating configuration and features on the fly from configfs. It is definitely not something that needs to be part of this set, nor have to be implemented any time soon, but is this something that is on your radar?
Lastly the "RFC" should be dropped for the fourth iteration, we are way passed that point now.
Thanks, Mathieu
Changes since v2:
- Added documentation file.
- Altered cs_syscfg driver to no longer be coresight_device based, and moved
to its own custom bus to remove it from the main coresight bus. (Mathieu) 3) Added configfs support to inspect and control loaded configurations and features. Allows listing of preset values (Yabin Cui) 4) Dropped sysfs support for adjusting feature parameters on the per device basis, in favour of a single point adjustment in configfs that is pushed to all device instances. 5) Altered how the config and preset command line options are handled in perf and the drivers. (Mathieu and Suzuki). 6) Fixes for various issues and technical points (Mathieu, Yabin)
Changes since v1:
- Moved preloaded configurations and features out of individual drivers.
- Added cs_syscfg driver to manage configurations and features. Individual
drivers register with cs_syscfg indicating support for config, and provide matching information that the system uses to load features into the drivers. This allows individual drivers to be updated on an as needed basis - and removes the need to consider devices that cannot benefit from configuration - static replicators, funnels, tpiu. 3) Added perf selection of configuarations. 4) Rebased onto the coresight module loading set.
To follow in future revisions / sets:- a) load of additional config and features by loadable module. b) load of additional config and features by configfs c) enhanced resource management for ETMv4 and checking features have sufficient resources to be enabled. d) ECT and CTI support for configuration and features.
Mike Leach (9): coresight: syscfg: Initial coresight system configuration coresight: syscfg: Add registration and feature loading for cs devices coresight: config: Add configuration and feature generic functions coresight: etm-perf: update to handle configuration selection coresight: etm4x: Add complex configuration handlers to etmv4 coresight: config: Add preloaded configurations coresight: syscfg: Add initial configfs support. coresight: syscfg: Allow update of feature params from configfs coresight: docs: Add documentation for CoreSight config.
.../trace/coresight/coresight-config.rst | 230 ++++++ Documentation/trace/coresight/coresight.rst | 16 + drivers/hwtracing/coresight/Makefile | 6 +- .../coresight/coresight-cfg-preload.c | 160 +++++ .../hwtracing/coresight/coresight-config.c | 392 +++++++++++ .../hwtracing/coresight/coresight-config.h | 311 +++++++++ drivers/hwtracing/coresight/coresight-core.c | 18 +- .../hwtracing/coresight/coresight-etm-perf.c | 166 ++++- .../hwtracing/coresight/coresight-etm-perf.h | 10 +- .../hwtracing/coresight/coresight-etm4x-cfg.c | 181 +++++ .../hwtracing/coresight/coresight-etm4x-cfg.h | 29 + .../coresight/coresight-etm4x-core.c | 36 +- .../coresight/coresight-etm4x-sysfs.c | 3 + .../coresight/coresight-syscfg-configfs.c | 421 +++++++++++ .../coresight/coresight-syscfg-configfs.h | 47 ++ .../hwtracing/coresight/coresight-syscfg.c | 656 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 83 +++ include/linux/coresight.h | 7 + 18 files changed, 2743 insertions(+), 29 deletions(-) create mode 100644 Documentation/trace/coresight/coresight-config.rst create mode 100644 drivers/hwtracing/coresight/coresight-cfg-preload.c create mode 100644 drivers/hwtracing/coresight/coresight-config.c create mode 100644 drivers/hwtracing/coresight/coresight-config.h create mode 100644 drivers/hwtracing/coresight/coresight-etm4x-cfg.c create mode 100644 drivers/hwtracing/coresight/coresight-etm4x-cfg.h create mode 100644 drivers/hwtracing/coresight/coresight-syscfg-configfs.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg-configfs.h create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.h
-- 2.17.1
Good day Mike,
On Thu, Dec 24, 2020 at 07:20:57PM +0000, Mike Leach wrote:
Hi MAthieu,
Thanks for the review as ever. Sorry its taken me a bit of time to respond, but there has been a bit of reworking to do.
Ok
I certainly agree with the _desc / _csdev convention, and the follow up set should address that.
Ok
The locking is also reconfigured as mentioned - so that it is simpler.
Ok
The general rules have been tightened. I was trying to allow features to be enabled independently of configurations when driving the system from configfs / sysfs rather than perf. But in the end there is little value in that approach.
Ok
As mentioned I have been working on follow up patches - which should be able to be split into smaller changesets. One is the dynamic loading of configurations, which will be either by loadable module, or configfs. The latter will allow the user to mkdir in the configs directory, and then load a binary blob via a "load" file. I do not believe that it is practicable to define an entire set of features with registers and configs via configfs - given that it is relatively inflexible in terms of adding files dynamically from a kernel perspective.
My view of the changes you are making is likely incomplete and as such it is probably a good idea to wait for another revision before providing further comments.
Let me know if there are things you need clarifications on that I have missed in your replies.
Thanks, Mathieu
That said, it may be possible later to add in a way to defne a configuration via configfs using previously defined named features only.
Regards
Mike
On Thu, 26 Nov 2020 at 18:52, Mathieu Poirier mathieu.poirier@linaro.org wrote:
Hi Mike,
On Fri, Oct 30, 2020 at 05:56:46PM +0000, Mike Leach wrote:
This patchset introduces initial concepts in CoreSight complex system configuration support.
Configurations consist of 2 elements:-
- Features - programming combinations for devices, applied to a class of
device on the system (all ETMv4), or individual devices. 2) Configurations - a set of programmed features used when the named configuration is selected.
Features and configurations are declared as a data table, a set of register, resource and parameter requirements. Features and configurations are loaded into the system by the virtual cs_syscfg device. This then matches features to any registered devices and loads the feature into them.
Individual device classes that support feature and configuration register with cs_syscfg.
Once loaded a configuration can be enabled for a specific trace run. Configurations are registered with the perf cs_etm event as entries in cs_etm/cs_config. These can be selected on the perf command line as follows:-
perf record -e cs_etm/<config_name>/ ...
This patch set has one pre-loaded configuration and feature. A named "strobing" feature is provided for ETMv4. A named "autofdo" configuration is provided. This configuration enables strobing on any ETM in used.
Thus the command: perf record -e cs_etm/autofdo/ ...
will trace the supplied application while enabling the "autofdo" configuation on each ETM as it is enabled by perf. This in turn will enable strobing for the ETM - with default parameters. Parameters can be adjusted using configfs.
The sink used in the trace run will be automatically selected.
A configuation can supply up to 15 of preset parameter values, which will subsitute in parameter values for any feature used in the configuration.
Selection of preset values as follows perf record -e cs_etm/autofdo,preset=1/ ...
(valid presets 1-N, where N is the number supplied in the configuration, not exceeding 15. preset=0 is the same as not selecting a preset.)
Applies to coresight/next (5.10-rc1 base)
I am done reviewing this third revision. I commented on a fair amount of things but that isn't unusual with this much code, especially when it is new code that doesn't have a precedent.
As I stated before I think the general architecture of the feature is sound. The concepts of XYZ_desc and XYZ_csdev have now sunk in and I quite like it. It will be really good when the naming convention is straighten out.
I spent a long time thinking about creating configuration and features on the fly from configfs. It is definitely not something that needs to be part of this set, nor have to be implemented any time soon, but is this something that is on your radar?
Lastly the "RFC" should be dropped for the fourth iteration, we are way passed that point now.
Thanks, Mathieu
Changes since v2:
- Added documentation file.
- Altered cs_syscfg driver to no longer be coresight_device based, and moved
to its own custom bus to remove it from the main coresight bus. (Mathieu) 3) Added configfs support to inspect and control loaded configurations and features. Allows listing of preset values (Yabin Cui) 4) Dropped sysfs support for adjusting feature parameters on the per device basis, in favour of a single point adjustment in configfs that is pushed to all device instances. 5) Altered how the config and preset command line options are handled in perf and the drivers. (Mathieu and Suzuki). 6) Fixes for various issues and technical points (Mathieu, Yabin)
Changes since v1:
- Moved preloaded configurations and features out of individual drivers.
- Added cs_syscfg driver to manage configurations and features. Individual
drivers register with cs_syscfg indicating support for config, and provide matching information that the system uses to load features into the drivers. This allows individual drivers to be updated on an as needed basis - and removes the need to consider devices that cannot benefit from configuration - static replicators, funnels, tpiu. 3) Added perf selection of configuarations. 4) Rebased onto the coresight module loading set.
To follow in future revisions / sets:- a) load of additional config and features by loadable module. b) load of additional config and features by configfs c) enhanced resource management for ETMv4 and checking features have sufficient resources to be enabled. d) ECT and CTI support for configuration and features.
Mike Leach (9): coresight: syscfg: Initial coresight system configuration coresight: syscfg: Add registration and feature loading for cs devices coresight: config: Add configuration and feature generic functions coresight: etm-perf: update to handle configuration selection coresight: etm4x: Add complex configuration handlers to etmv4 coresight: config: Add preloaded configurations coresight: syscfg: Add initial configfs support. coresight: syscfg: Allow update of feature params from configfs coresight: docs: Add documentation for CoreSight config.
.../trace/coresight/coresight-config.rst | 230 ++++++ Documentation/trace/coresight/coresight.rst | 16 + drivers/hwtracing/coresight/Makefile | 6 +- .../coresight/coresight-cfg-preload.c | 160 +++++ .../hwtracing/coresight/coresight-config.c | 392 +++++++++++ .../hwtracing/coresight/coresight-config.h | 311 +++++++++ drivers/hwtracing/coresight/coresight-core.c | 18 +- .../hwtracing/coresight/coresight-etm-perf.c | 166 ++++- .../hwtracing/coresight/coresight-etm-perf.h | 10 +- .../hwtracing/coresight/coresight-etm4x-cfg.c | 181 +++++ .../hwtracing/coresight/coresight-etm4x-cfg.h | 29 + .../coresight/coresight-etm4x-core.c | 36 +- .../coresight/coresight-etm4x-sysfs.c | 3 + .../coresight/coresight-syscfg-configfs.c | 421 +++++++++++ .../coresight/coresight-syscfg-configfs.h | 47 ++ .../hwtracing/coresight/coresight-syscfg.c | 656 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 83 +++ include/linux/coresight.h | 7 + 18 files changed, 2743 insertions(+), 29 deletions(-) create mode 100644 Documentation/trace/coresight/coresight-config.rst create mode 100644 drivers/hwtracing/coresight/coresight-cfg-preload.c create mode 100644 drivers/hwtracing/coresight/coresight-config.c create mode 100644 drivers/hwtracing/coresight/coresight-config.h create mode 100644 drivers/hwtracing/coresight/coresight-etm4x-cfg.c create mode 100644 drivers/hwtracing/coresight/coresight-etm4x-cfg.h create mode 100644 drivers/hwtracing/coresight/coresight-syscfg-configfs.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg-configfs.h create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.h
-- 2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK