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. (at present these default parameters can be altered using sysfs for each individual ETM - but this is under review).
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.)
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.
Applies to coresight/next (5.9-rc1 base) with the coresight module load set [1] applied.
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. e) documentation file.
[1] https://lists.linaro.org/pipermail/coresight/2020-August/004704.html
Mike Leach (8): coresight: syscfg: Initial coresight system configuration coresight: syscfg: Add loading of features and configurations coresight: syscfg: Add registration and feature loading for cs devices coresight: config: Add configuration and feature generic functions perf: cs_etm: update cs_etm processing to allow configuration selection coresight: etm-perf: update to handle configuration selection coresight: etm4x: Add complex configuration handlers to etmv4 coresight: config: Add preloaded configurations
drivers/hwtracing/coresight/Makefile | 6 +- .../coresight/coresight-cfg-preload.c | 165 +++++ .../hwtracing/coresight/coresight-config.c | 565 ++++++++++++++++++ .../hwtracing/coresight/coresight-config.h | 289 +++++++++ drivers/hwtracing/coresight/coresight-core.c | 36 +- .../hwtracing/coresight/coresight-etm-perf.c | 91 ++- .../hwtracing/coresight/coresight-etm-perf.h | 8 +- .../hwtracing/coresight/coresight-etm4x-cfg.c | 226 +++++++ .../hwtracing/coresight/coresight-etm4x-cfg.h | 29 + .../coresight/coresight-etm4x-core.c | 30 +- .../coresight/coresight-etm4x-sysfs.c | 3 + .../hwtracing/coresight/coresight-syscfg.c | 527 ++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 90 +++ include/linux/coresight-pmu.h | 3 + include/linux/coresight.h | 8 + tools/include/linux/coresight-pmu.h | 3 + tools/perf/arch/arm/util/cs-etm.c | 17 +- 17 files changed, 2066 insertions(+), 30 deletions(-) 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.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.h
Creates a virtual coresight device on the bus to handle system configuration of the coresight infrastructure.
The device 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 updates the coresight core initialisation to create the single instance of the cs_syscfg coresight system device, on the coresight bus.
Signed-off-by: Mike Leach mike.leach@linaro.org --- drivers/hwtracing/coresight/Makefile | 2 +- drivers/hwtracing/coresight/coresight-core.c | 29 +++- .../hwtracing/coresight/coresight-etm-perf.c | 2 +- .../hwtracing/coresight/coresight-etm-perf.h | 2 +- .../hwtracing/coresight/coresight-syscfg.c | 136 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 39 +++++ include/linux/coresight.h | 1 + 7 files changed, 207 insertions(+), 4 deletions(-) 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 1b35b55bd420..3605dd770664 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-core.c b/drivers/hwtracing/coresight/coresight-core.c index bf6edf468963..91f1fbd7d51d 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);
@@ -1669,8 +1670,17 @@ char *coresight_alloc_device_name(struct coresight_dev_list *dict, } EXPORT_SYMBOL_GPL(coresight_alloc_device_name);
+/* match for virtual csdevs that have no underlying amba device */ +static int coresight_bus_match(struct device *dev, struct device_driver *drv) +{ + struct coresight_device *csdev = to_coresight_device(dev); + + return csdev->type == CORESIGHT_DEV_TYPE_SYSCFG; +} + struct bus_type coresight_bustype = { .name = "coresight", + .match = coresight_bus_match, };
static int __init coresight_init(void) @@ -1683,13 +1693,29 @@ static int __init coresight_init(void)
ret = etm_perf_init(); if (ret) - bus_unregister(&coresight_bustype); + goto exit_bus_unregister; + + /* initialise the coresight syscfg driver and device */ + ret = cscfg_driver_init(); + if (ret) + goto exit_perf_clear; + + ret = cscfg_create_device(); + if (!ret) + return 0;
+ cscfg_driver_exit(); +exit_perf_clear: + etm_perf_exit(); +exit_bus_unregister: + bus_unregister(&coresight_bustype); return ret; }
static void __exit coresight_exit(void) { + cscfg_clear_device(); + cscfg_driver_exit(); etm_perf_exit(); bus_unregister(&coresight_bustype); } @@ -1700,3 +1726,4 @@ module_exit(coresight_exit); MODULE_AUTHOR("Pratik Patel pratikp@codeaurora.org"); MODULE_AUTHOR("Mathieu Poirier mathieu.poirier@linaro.org"); MODULE_DESCRIPTION("Arm CoreSight tracer driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 668b3ff11576..2d619b764738 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -619,7 +619,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..badef8cfc7f8 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -0,0 +1,136 @@ +// 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-syscfg.h" + + +/* + * cs_syscfg device is a virtual device managing the overall cs system. + * + * It allows the loading of configurations and features, and loads these into + * coresight devices as appropriate. + */ + +static DEFINE_MUTEX(cs_cfg_mutex); + +/* only one of these */ +static struct cs_cfg_device *cscfg_dev; + +static struct device_type cscfg_dev_type = { + .name = "cs_syscfg", +}; + +#define to_device_cscfg() (&cscfg_dev->csdev.dev) +#define to_coresight_device_cscfg() (&cscfg_dev->csdev) + + +/* cs_syscfg device instance handling */ +static void cscfg_device_release(struct device *dev) +{ + kfree(cscfg_dev->csdev.pdata); + kfree(cscfg_dev); + cscfg_dev = NULL; +} + +int cscfg_create_device(void) +{ + struct device *dev; + struct coresight_device *csdev; + struct coresight_platform_data *pdata = NULL; + int err = -ENOMEM; + + mutex_lock(&cs_cfg_mutex); + if (cscfg_dev) { + err = -EINVAL; + goto create_dev_exit_unlock; + } + + cscfg_dev = kzalloc(sizeof(*cscfg_dev), GFP_KERNEL); + if (!cscfg_dev) + goto create_dev_exit_unlock; + + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + kfree(cscfg_dev); + cscfg_dev = NULL; + goto create_dev_exit_unlock; + } + + /* setup the device */ + dev = to_device_cscfg(); + dev_set_name(dev, "cs_syscfg"); + dev->bus = &coresight_bustype; + dev->parent = &platform_bus; + dev->type = &cscfg_dev_type; + + /* setup a coresight device */ + csdev = to_coresight_device_cscfg(); + csdev->type = CORESIGHT_DEV_TYPE_SYSCFG; + csdev->pdata = pdata; + csdev->orphan = false; + csdev->dev.release = cscfg_device_release; + + err = device_register(dev); + +create_dev_exit_unlock: + mutex_unlock(&cs_cfg_mutex); + return err; + +} + +void cscfg_clear_device(void) +{ + mutex_lock(&cs_cfg_mutex); + device_unregister(to_device_cscfg()); + mutex_unlock(&cs_cfg_mutex); +} + +/* Finish allocating resources and load built-in configurations and features. */ +static int cscfg_probe(struct device *dev) +{ + int ret = 0; + + /* there can be only one... */ + if (dev != to_device_cscfg()) + return -EINVAL; + + /* + * No actual hardware to handle, just allocate resources. + * Probe is triggered when the core calls cscfg_create_device() to + * create the device, so the mutex is already held. + */ + + INIT_LIST_HEAD(&cscfg_dev->dev_list); + INIT_LIST_HEAD(&cscfg_dev->feat_list); + INIT_LIST_HEAD(&cscfg_dev->config_list); + + dev_info(dev, "CSCFG initialised"); + return ret; +} + +/* driver initialisation */ +static struct cs_cfg_driver cs_config_driver = { + .drv = { + .name = "coresight-syscfg", + .owner = THIS_MODULE, + .suppress_bind_attrs = true, + .probe = cscfg_probe, + }, +}; + +/* called from coresight core init */ +int __init cscfg_driver_init(void) +{ + cs_config_driver.drv.bus = &coresight_bustype; + return driver_register(&cs_config_driver.drv); +} + +void cscfg_driver_exit(void) +{ + driver_unregister(&cs_config_driver.drv); +} diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h new file mode 100644 index 000000000000..20ccca5e4151 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -0,0 +1,39 @@ +/* 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> + +/** + * System configuration device. + * + * @csdev: The coresight device instance. + * @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. + */ +struct cs_cfg_device { + struct coresight_device csdev; + struct list_head dev_list; + struct list_head feat_list; + struct list_head config_list; + int nr_csdev; +}; + +/* basic device driver */ +struct cs_cfg_driver { + struct device_driver drv; +}; + +/* internal core operations for cscfg */ +int cscfg_create_device(void); +void cscfg_clear_device(void); +int __init cscfg_driver_init(void); +void cscfg_driver_exit(void); + +#endif /* CORESIGHT_SYSCFG_H */ diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 7d3c87e5b97c..ed0a9d938303 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -42,6 +42,7 @@ enum coresight_dev_type { CORESIGHT_DEV_TYPE_SOURCE, CORESIGHT_DEV_TYPE_HELPER, CORESIGHT_DEV_TYPE_ECT, + CORESIGHT_DEV_TYPE_SYSCFG, };
enum coresight_dev_subtype_sink {
Good afternoon Mike,
On Thu, Aug 27, 2020 at 03:34:04PM +0100, Mike Leach wrote:
Creates a virtual coresight device on the bus to handle system configuration of the coresight infrastructure.
The device 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 updates the coresight core initialisation to create the single instance of the cs_syscfg coresight system device, on the coresight bus.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 2 +- drivers/hwtracing/coresight/coresight-core.c | 29 +++- .../hwtracing/coresight/coresight-etm-perf.c | 2 +- .../hwtracing/coresight/coresight-etm-perf.h | 2 +- .../hwtracing/coresight/coresight-syscfg.c | 136 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 39 +++++ include/linux/coresight.h | 1 + 7 files changed, 207 insertions(+), 4 deletions(-) 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 1b35b55bd420..3605dd770664 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-core.c b/drivers/hwtracing/coresight/coresight-core.c index bf6edf468963..91f1fbd7d51d 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); @@ -1669,8 +1670,17 @@ char *coresight_alloc_device_name(struct coresight_dev_list *dict, } EXPORT_SYMBOL_GPL(coresight_alloc_device_name); +/* match for virtual csdevs that have no underlying amba device */ +static int coresight_bus_match(struct device *dev, struct device_driver *drv) +{
- struct coresight_device *csdev = to_coresight_device(dev);
- return csdev->type == CORESIGHT_DEV_TYPE_SYSCFG;
+}
struct bus_type coresight_bustype = { .name = "coresight",
- .match = coresight_bus_match,
}; static int __init coresight_init(void) @@ -1683,13 +1693,29 @@ static int __init coresight_init(void) ret = etm_perf_init(); if (ret)
bus_unregister(&coresight_bustype);
goto exit_bus_unregister;
- /* initialise the coresight syscfg driver and device */
- ret = cscfg_driver_init();
- if (ret)
goto exit_perf_clear;
- ret = cscfg_create_device();
- if (!ret)
return 0;
- cscfg_driver_exit();
+exit_perf_clear:
- etm_perf_exit();
+exit_bus_unregister:
- bus_unregister(&coresight_bustype); return ret;
} static void __exit coresight_exit(void) {
- cscfg_clear_device();
- cscfg_driver_exit(); etm_perf_exit(); bus_unregister(&coresight_bustype);
} @@ -1700,3 +1726,4 @@ module_exit(coresight_exit); MODULE_AUTHOR("Pratik Patel pratikp@codeaurora.org"); MODULE_AUTHOR("Mathieu Poirier mathieu.poirier@linaro.org"); MODULE_DESCRIPTION("Arm CoreSight tracer driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 668b3ff11576..2d619b764738 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -619,7 +619,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..badef8cfc7f8 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -0,0 +1,136 @@ +// 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-syscfg.h"
+/*
- cs_syscfg device is a virtual device managing the overall cs system.
- It allows the loading of configurations and features, and loads these into
- coresight devices as appropriate.
- */
+static DEFINE_MUTEX(cs_cfg_mutex);
+/* only one of these */ +static struct cs_cfg_device *cscfg_dev;
+static struct device_type cscfg_dev_type = {
- .name = "cs_syscfg",
+};
+#define to_device_cscfg() (&cscfg_dev->csdev.dev) +#define to_coresight_device_cscfg() (&cscfg_dev->csdev)
+/* cs_syscfg device instance handling */ +static void cscfg_device_release(struct device *dev) +{
- kfree(cscfg_dev->csdev.pdata);
- kfree(cscfg_dev);
- cscfg_dev = NULL;
+}
+int cscfg_create_device(void) +{
- struct device *dev;
- struct coresight_device *csdev;
- struct coresight_platform_data *pdata = NULL;
- int err = -ENOMEM;
- mutex_lock(&cs_cfg_mutex);
- if (cscfg_dev) {
err = -EINVAL;
goto create_dev_exit_unlock;
- }
- cscfg_dev = kzalloc(sizeof(*cscfg_dev), GFP_KERNEL);
- if (!cscfg_dev)
goto create_dev_exit_unlock;
- pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
kfree(cscfg_dev);
cscfg_dev = NULL;
goto create_dev_exit_unlock;
- }
- /* setup the device */
- dev = to_device_cscfg();
- dev_set_name(dev, "cs_syscfg");
- dev->bus = &coresight_bustype;
- dev->parent = &platform_bus;
- dev->type = &cscfg_dev_type;
As far as I can tell setting the device type doesn't do anything.
- /* setup a coresight device */
- csdev = to_coresight_device_cscfg();
- csdev->type = CORESIGHT_DEV_TYPE_SYSCFG;
- csdev->pdata = pdata;
- csdev->orphan = false;
- csdev->dev.release = cscfg_device_release;
I also fail to understand the requirement to use a coresight_device and to add it to the coresigh bus. To me it seems odd to have it there since it has no interaction with any of the other CS devices.
- err = device_register(dev);
+create_dev_exit_unlock:
- mutex_unlock(&cs_cfg_mutex);
- return err;
+}
+void cscfg_clear_device(void) +{
- mutex_lock(&cs_cfg_mutex);
- device_unregister(to_device_cscfg());
- mutex_unlock(&cs_cfg_mutex);
+}
+/* Finish allocating resources and load built-in configurations and features. */ +static int cscfg_probe(struct device *dev) +{
- int ret = 0;
- /* there can be only one... */
- if (dev != to_device_cscfg())
return -EINVAL;
- /*
* No actual hardware to handle, just allocate resources.
* Probe is triggered when the core calls cscfg_create_device() to
* create the device, so the mutex is already held.
*/
- INIT_LIST_HEAD(&cscfg_dev->dev_list);
- INIT_LIST_HEAD(&cscfg_dev->feat_list);
- INIT_LIST_HEAD(&cscfg_dev->config_list);
- dev_info(dev, "CSCFG initialised");
- return ret;
+}
+/* driver initialisation */ +static struct cs_cfg_driver cs_config_driver = {
This set uses cs_cfg_ and cscfg_ to declare structures and function, making it very difficult to read the code. Please pick one (I'd go with the latter but that's a personal opinion) and stick with it.
I also don't think the functionality provided in this file need to be a driver, it can simply be a set of functions handling configuration and features.
- .drv = {
.name = "coresight-syscfg",
.owner = THIS_MODULE,
.suppress_bind_attrs = true,
.probe = cscfg_probe,
- },
+};
+/* called from coresight core init */ +int __init cscfg_driver_init(void) +{
- cs_config_driver.drv.bus = &coresight_bustype;
- return driver_register(&cs_config_driver.drv);
+}
+void cscfg_driver_exit(void) +{
- driver_unregister(&cs_config_driver.drv);
+} diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h new file mode 100644 index 000000000000..20ccca5e4151 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -0,0 +1,39 @@ +/* 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>
+/**
- System configuration device.
- @csdev: The coresight device instance.
- @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.
- */
+struct cs_cfg_device {
- struct coresight_device csdev;
- struct list_head dev_list;
- struct list_head feat_list;
- struct list_head config_list;
- int nr_csdev;
+};
+/* basic device driver */ +struct cs_cfg_driver {
- struct device_driver drv;
+};
+/* internal core operations for cscfg */ +int cscfg_create_device(void); +void cscfg_clear_device(void); +int __init cscfg_driver_init(void); +void cscfg_driver_exit(void);
+#endif /* CORESIGHT_SYSCFG_H */ diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 7d3c87e5b97c..ed0a9d938303 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -42,6 +42,7 @@ enum coresight_dev_type { CORESIGHT_DEV_TYPE_SOURCE, CORESIGHT_DEV_TYPE_HELPER, CORESIGHT_DEV_TYPE_ECT,
- CORESIGHT_DEV_TYPE_SYSCFG,
}; enum coresight_dev_subtype_sink { -- 2.17.1
Hi Mathieu,
On Thu, 1 Oct 2020 at 21:07, Mathieu Poirier mathieu.poirier@linaro.org wrote:
Good afternoon Mike,
On Thu, Aug 27, 2020 at 03:34:04PM +0100, Mike Leach wrote:
Creates a virtual coresight device on the bus to handle system configuration of the coresight infrastructure.
The device 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 updates the coresight core initialisation to create the single instance of the cs_syscfg coresight system device, on the coresight bus.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 2 +- drivers/hwtracing/coresight/coresight-core.c | 29 +++- .../hwtracing/coresight/coresight-etm-perf.c | 2 +- .../hwtracing/coresight/coresight-etm-perf.h | 2 +- .../hwtracing/coresight/coresight-syscfg.c | 136 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 39 +++++ include/linux/coresight.h | 1 + 7 files changed, 207 insertions(+), 4 deletions(-) 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 1b35b55bd420..3605dd770664 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-core.c b/drivers/hwtracing/coresight/coresight-core.c index bf6edf468963..91f1fbd7d51d 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);
@@ -1669,8 +1670,17 @@ char *coresight_alloc_device_name(struct coresight_dev_list *dict, } EXPORT_SYMBOL_GPL(coresight_alloc_device_name);
+/* match for virtual csdevs that have no underlying amba device */ +static int coresight_bus_match(struct device *dev, struct device_driver *drv) +{
struct coresight_device *csdev = to_coresight_device(dev);
return csdev->type == CORESIGHT_DEV_TYPE_SYSCFG;
+}
struct bus_type coresight_bustype = { .name = "coresight",
.match = coresight_bus_match,
};
static int __init coresight_init(void) @@ -1683,13 +1693,29 @@ static int __init coresight_init(void)
ret = etm_perf_init(); if (ret)
bus_unregister(&coresight_bustype);
goto exit_bus_unregister;
/* initialise the coresight syscfg driver and device */
ret = cscfg_driver_init();
if (ret)
goto exit_perf_clear;
ret = cscfg_create_device();
if (!ret)
return 0;
cscfg_driver_exit();
+exit_perf_clear:
etm_perf_exit();
+exit_bus_unregister:
bus_unregister(&coresight_bustype); return ret;
}
static void __exit coresight_exit(void) {
cscfg_clear_device();
cscfg_driver_exit(); etm_perf_exit(); bus_unregister(&coresight_bustype);
} @@ -1700,3 +1726,4 @@ module_exit(coresight_exit); MODULE_AUTHOR("Pratik Patel pratikp@codeaurora.org"); MODULE_AUTHOR("Mathieu Poirier mathieu.poirier@linaro.org"); MODULE_DESCRIPTION("Arm CoreSight tracer driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 668b3ff11576..2d619b764738 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -619,7 +619,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..badef8cfc7f8 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -0,0 +1,136 @@ +// 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-syscfg.h"
+/*
- cs_syscfg device is a virtual device managing the overall cs system.
- It allows the loading of configurations and features, and loads these into
- coresight devices as appropriate.
- */
+static DEFINE_MUTEX(cs_cfg_mutex);
+/* only one of these */ +static struct cs_cfg_device *cscfg_dev;
+static struct device_type cscfg_dev_type = {
.name = "cs_syscfg",
+};
+#define to_device_cscfg() (&cscfg_dev->csdev.dev) +#define to_coresight_device_cscfg() (&cscfg_dev->csdev)
+/* cs_syscfg device instance handling */ +static void cscfg_device_release(struct device *dev) +{
kfree(cscfg_dev->csdev.pdata);
kfree(cscfg_dev);
cscfg_dev = NULL;
+}
+int cscfg_create_device(void) +{
struct device *dev;
struct coresight_device *csdev;
struct coresight_platform_data *pdata = NULL;
int err = -ENOMEM;
mutex_lock(&cs_cfg_mutex);
if (cscfg_dev) {
err = -EINVAL;
goto create_dev_exit_unlock;
}
cscfg_dev = kzalloc(sizeof(*cscfg_dev), GFP_KERNEL);
if (!cscfg_dev)
goto create_dev_exit_unlock;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
kfree(cscfg_dev);
cscfg_dev = NULL;
goto create_dev_exit_unlock;
}
/* setup the device */
dev = to_device_cscfg();
dev_set_name(dev, "cs_syscfg");
dev->bus = &coresight_bustype;
dev->parent = &platform_bus;
dev->type = &cscfg_dev_type;
As far as I can tell setting the device type doesn't do anything.
It provides name for the entry in /sys/devices/... - ie.
/sys/devices/platform/cs_syscfg
/* setup a coresight device */
csdev = to_coresight_device_cscfg();
csdev->type = CORESIGHT_DEV_TYPE_SYSCFG;
csdev->pdata = pdata;
csdev->orphan = false;
csdev->dev.release = cscfg_device_release;
I also fail to understand the requirement to use a coresight_device and to add it to the coresigh bus. To me it seems odd to have it there since it has no interaction with any of the other CS devices.
Not at this early stage - this patch just introduces the device, without much functionality at present. But later on it becomes capable of loading features and configurations and enabling them across relevant devices on the bus.
err = device_register(dev);
+create_dev_exit_unlock:
mutex_unlock(&cs_cfg_mutex);
return err;
+}
+void cscfg_clear_device(void) +{
mutex_lock(&cs_cfg_mutex);
device_unregister(to_device_cscfg());
mutex_unlock(&cs_cfg_mutex);
+}
+/* Finish allocating resources and load built-in configurations and features. */ +static int cscfg_probe(struct device *dev) +{
int ret = 0;
/* there can be only one... */
if (dev != to_device_cscfg())
return -EINVAL;
/*
* No actual hardware to handle, just allocate resources.
* Probe is triggered when the core calls cscfg_create_device() to
* create the device, so the mutex is already held.
*/
INIT_LIST_HEAD(&cscfg_dev->dev_list);
INIT_LIST_HEAD(&cscfg_dev->feat_list);
INIT_LIST_HEAD(&cscfg_dev->config_list);
dev_info(dev, "CSCFG initialised");
return ret;
+}
+/* driver initialisation */ +static struct cs_cfg_driver cs_config_driver = {
This set uses cs_cfg_ and cscfg_ to declare structures and function, making it very difficult to read the code. Please pick one (I'd go with the latter but that's a personal opinion) and stick with it.
Agreed - I started off using cs_cfg_.. for data structures, and cscfg_... for functions - but I'll use just the one as it is easier.
I also don't think the functionality provided in this file need to be a driver, it can simply be a set of functions handling configuration and features.
The thinking here was that:- 1) a virtual device is a good way of modelling functionality that affects the entire coresight subsystem - i.e. treat it as a compound device. 2) A device object / kobject is required to support some kernel functionality such as sysfs and configfs when that is added.
That said, my work on configfs - which is not included in this set - would seem to indicate an explicit driver may not be needed, and a set of callback functions and data structures defined in the coresight module may be sufficient. So it may be possible to drop the driver abastaction for now and re-introduce if it does become necessary.
Thanks for the review
Mike
.drv = {
.name = "coresight-syscfg",
.owner = THIS_MODULE,
.suppress_bind_attrs = true,
.probe = cscfg_probe,
},
+};
+/* called from coresight core init */ +int __init cscfg_driver_init(void) +{
cs_config_driver.drv.bus = &coresight_bustype;
return driver_register(&cs_config_driver.drv);
+}
+void cscfg_driver_exit(void) +{
driver_unregister(&cs_config_driver.drv);
+} diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h new file mode 100644 index 000000000000..20ccca5e4151 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -0,0 +1,39 @@ +/* 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>
+/**
- System configuration device.
- @csdev: The coresight device instance.
- @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.
- */
+struct cs_cfg_device {
struct coresight_device csdev;
struct list_head dev_list;
struct list_head feat_list;
struct list_head config_list;
int nr_csdev;
+};
+/* basic device driver */ +struct cs_cfg_driver {
struct device_driver drv;
+};
+/* internal core operations for cscfg */ +int cscfg_create_device(void); +void cscfg_clear_device(void); +int __init cscfg_driver_init(void); +void cscfg_driver_exit(void);
+#endif /* CORESIGHT_SYSCFG_H */ diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 7d3c87e5b97c..ed0a9d938303 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -42,6 +42,7 @@ enum coresight_dev_type { CORESIGHT_DEV_TYPE_SOURCE, CORESIGHT_DEV_TYPE_HELPER, CORESIGHT_DEV_TYPE_ECT,
CORESIGHT_DEV_TYPE_SYSCFG,
};
enum coresight_dev_subtype_sink {
2.17.1
On Tue, Oct 06, 2020 at 11:40:46AM +0100, Mike Leach wrote:
Hi Mathieu,
On Thu, 1 Oct 2020 at 21:07, Mathieu Poirier mathieu.poirier@linaro.org wrote:
Good afternoon Mike,
On Thu, Aug 27, 2020 at 03:34:04PM +0100, Mike Leach wrote:
Creates a virtual coresight device on the bus to handle system configuration of the coresight infrastructure.
The device 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 updates the coresight core initialisation to create the single instance of the cs_syscfg coresight system device, on the coresight bus.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 2 +- drivers/hwtracing/coresight/coresight-core.c | 29 +++- .../hwtracing/coresight/coresight-etm-perf.c | 2 +- .../hwtracing/coresight/coresight-etm-perf.h | 2 +- .../hwtracing/coresight/coresight-syscfg.c | 136 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 39 +++++ include/linux/coresight.h | 1 + 7 files changed, 207 insertions(+), 4 deletions(-) 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 1b35b55bd420..3605dd770664 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-core.c b/drivers/hwtracing/coresight/coresight-core.c index bf6edf468963..91f1fbd7d51d 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);
@@ -1669,8 +1670,17 @@ char *coresight_alloc_device_name(struct coresight_dev_list *dict, } EXPORT_SYMBOL_GPL(coresight_alloc_device_name);
+/* match for virtual csdevs that have no underlying amba device */ +static int coresight_bus_match(struct device *dev, struct device_driver *drv) +{
struct coresight_device *csdev = to_coresight_device(dev);
return csdev->type == CORESIGHT_DEV_TYPE_SYSCFG;
+}
struct bus_type coresight_bustype = { .name = "coresight",
.match = coresight_bus_match,
};
static int __init coresight_init(void) @@ -1683,13 +1693,29 @@ static int __init coresight_init(void)
ret = etm_perf_init(); if (ret)
bus_unregister(&coresight_bustype);
goto exit_bus_unregister;
/* initialise the coresight syscfg driver and device */
ret = cscfg_driver_init();
if (ret)
goto exit_perf_clear;
ret = cscfg_create_device();
if (!ret)
return 0;
cscfg_driver_exit();
+exit_perf_clear:
etm_perf_exit();
+exit_bus_unregister:
bus_unregister(&coresight_bustype); return ret;
}
static void __exit coresight_exit(void) {
cscfg_clear_device();
cscfg_driver_exit(); etm_perf_exit(); bus_unregister(&coresight_bustype);
} @@ -1700,3 +1726,4 @@ module_exit(coresight_exit); MODULE_AUTHOR("Pratik Patel pratikp@codeaurora.org"); MODULE_AUTHOR("Mathieu Poirier mathieu.poirier@linaro.org"); MODULE_DESCRIPTION("Arm CoreSight tracer driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 668b3ff11576..2d619b764738 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -619,7 +619,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..badef8cfc7f8 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -0,0 +1,136 @@ +// 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-syscfg.h"
+/*
- cs_syscfg device is a virtual device managing the overall cs system.
- It allows the loading of configurations and features, and loads these into
- coresight devices as appropriate.
- */
+static DEFINE_MUTEX(cs_cfg_mutex);
+/* only one of these */ +static struct cs_cfg_device *cscfg_dev;
+static struct device_type cscfg_dev_type = {
.name = "cs_syscfg",
+};
+#define to_device_cscfg() (&cscfg_dev->csdev.dev) +#define to_coresight_device_cscfg() (&cscfg_dev->csdev)
+/* cs_syscfg device instance handling */ +static void cscfg_device_release(struct device *dev) +{
kfree(cscfg_dev->csdev.pdata);
kfree(cscfg_dev);
cscfg_dev = NULL;
+}
+int cscfg_create_device(void) +{
struct device *dev;
struct coresight_device *csdev;
struct coresight_platform_data *pdata = NULL;
int err = -ENOMEM;
mutex_lock(&cs_cfg_mutex);
if (cscfg_dev) {
err = -EINVAL;
goto create_dev_exit_unlock;
}
cscfg_dev = kzalloc(sizeof(*cscfg_dev), GFP_KERNEL);
if (!cscfg_dev)
goto create_dev_exit_unlock;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
kfree(cscfg_dev);
cscfg_dev = NULL;
goto create_dev_exit_unlock;
}
/* setup the device */
dev = to_device_cscfg();
dev_set_name(dev, "cs_syscfg");
dev->bus = &coresight_bustype;
dev->parent = &platform_bus;
dev->type = &cscfg_dev_type;
As far as I can tell setting the device type doesn't do anything.
It provides name for the entry in /sys/devices/... - ie.
/sys/devices/platform/cs_syscfg
The device name is set in dev_set_name(), which is sufficient for proper labelling in sysfs.
/* setup a coresight device */
csdev = to_coresight_device_cscfg();
csdev->type = CORESIGHT_DEV_TYPE_SYSCFG;
csdev->pdata = pdata;
csdev->orphan = false;
csdev->dev.release = cscfg_device_release;
I also fail to understand the requirement to use a coresight_device and to add it to the coresigh bus. To me it seems odd to have it there since it has no interaction with any of the other CS devices.
Not at this early stage - this patch just introduces the device, without much functionality at present. But later on it becomes capable of loading features and configurations and enabling them across relevant devices on the bus.
The bus_type is very rich in feature and should provide everything you need. Using a csdev should be the very last option.
err = device_register(dev);
+create_dev_exit_unlock:
mutex_unlock(&cs_cfg_mutex);
return err;
+}
+void cscfg_clear_device(void) +{
mutex_lock(&cs_cfg_mutex);
device_unregister(to_device_cscfg());
mutex_unlock(&cs_cfg_mutex);
+}
+/* Finish allocating resources and load built-in configurations and features. */ +static int cscfg_probe(struct device *dev) +{
int ret = 0;
/* there can be only one... */
if (dev != to_device_cscfg())
return -EINVAL;
/*
* No actual hardware to handle, just allocate resources.
* Probe is triggered when the core calls cscfg_create_device() to
* create the device, so the mutex is already held.
*/
INIT_LIST_HEAD(&cscfg_dev->dev_list);
INIT_LIST_HEAD(&cscfg_dev->feat_list);
INIT_LIST_HEAD(&cscfg_dev->config_list);
dev_info(dev, "CSCFG initialised");
return ret;
+}
+/* driver initialisation */ +static struct cs_cfg_driver cs_config_driver = {
This set uses cs_cfg_ and cscfg_ to declare structures and function, making it very difficult to read the code. Please pick one (I'd go with the latter but that's a personal opinion) and stick with it.
Agreed - I started off using cs_cfg_.. for data structures, and cscfg_... for functions - but I'll use just the one as it is easier.
I also don't think the functionality provided in this file need to be a driver, it can simply be a set of functions handling configuration and features.
The thinking here was that:-
- a virtual device is a good way of modelling functionality that
affects the entire coresight subsystem - i.e. treat it as a compound device. 2) A device object / kobject is required to support some kernel functionality such as sysfs and configfs when that is added.
That said, my work on configfs - which is not included in this set - would seem to indicate an explicit driver may not be needed, and a set of callback functions and data structures defined in the coresight module may be sufficient. So it may be possible to drop the driver abastaction for now and re-introduce if it does become necessary.
I think that makes sense and will help making this set smaller.
Thanks for the review
I will continue with patch 3 and 4 today.
Mike
.drv = {
.name = "coresight-syscfg",
.owner = THIS_MODULE,
.suppress_bind_attrs = true,
.probe = cscfg_probe,
},
+};
+/* called from coresight core init */ +int __init cscfg_driver_init(void) +{
cs_config_driver.drv.bus = &coresight_bustype;
return driver_register(&cs_config_driver.drv);
+}
+void cscfg_driver_exit(void) +{
driver_unregister(&cs_config_driver.drv);
+} diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h new file mode 100644 index 000000000000..20ccca5e4151 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -0,0 +1,39 @@ +/* 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>
+/**
- System configuration device.
- @csdev: The coresight device instance.
- @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.
- */
+struct cs_cfg_device {
struct coresight_device csdev;
struct list_head dev_list;
struct list_head feat_list;
struct list_head config_list;
int nr_csdev;
+};
+/* basic device driver */ +struct cs_cfg_driver {
struct device_driver drv;
+};
+/* internal core operations for cscfg */ +int cscfg_create_device(void); +void cscfg_clear_device(void); +int __init cscfg_driver_init(void); +void cscfg_driver_exit(void);
+#endif /* CORESIGHT_SYSCFG_H */ diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 7d3c87e5b97c..ed0a9d938303 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -42,6 +42,7 @@ enum coresight_dev_type { CORESIGHT_DEV_TYPE_SOURCE, CORESIGHT_DEV_TYPE_HELPER, CORESIGHT_DEV_TYPE_ECT,
CORESIGHT_DEV_TYPE_SYSCFG,
};
enum coresight_dev_subtype_sink {
2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
Hi Mathieu,
On Tue, 6 Oct 2020 at 18:31, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Tue, Oct 06, 2020 at 11:40:46AM +0100, Mike Leach wrote:
Hi Mathieu,
On Thu, 1 Oct 2020 at 21:07, Mathieu Poirier mathieu.poirier@linaro.org wrote:
Good afternoon Mike,
On Thu, Aug 27, 2020 at 03:34:04PM +0100, Mike Leach wrote:
Creates a virtual coresight device on the bus to handle system configuration of the coresight infrastructure.
The device 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 updates the coresight core initialisation to create the single instance of the cs_syscfg coresight system device, on the coresight bus.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 2 +- drivers/hwtracing/coresight/coresight-core.c | 29 +++- .../hwtracing/coresight/coresight-etm-perf.c | 2 +- .../hwtracing/coresight/coresight-etm-perf.h | 2 +- .../hwtracing/coresight/coresight-syscfg.c | 136 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 39 +++++ include/linux/coresight.h | 1 + 7 files changed, 207 insertions(+), 4 deletions(-) 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 1b35b55bd420..3605dd770664 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-core.c b/drivers/hwtracing/coresight/coresight-core.c index bf6edf468963..91f1fbd7d51d 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);
@@ -1669,8 +1670,17 @@ char *coresight_alloc_device_name(struct coresight_dev_list *dict, } EXPORT_SYMBOL_GPL(coresight_alloc_device_name);
+/* match for virtual csdevs that have no underlying amba device */ +static int coresight_bus_match(struct device *dev, struct device_driver *drv) +{
struct coresight_device *csdev = to_coresight_device(dev);
return csdev->type == CORESIGHT_DEV_TYPE_SYSCFG;
+}
struct bus_type coresight_bustype = { .name = "coresight",
.match = coresight_bus_match,
};
static int __init coresight_init(void) @@ -1683,13 +1693,29 @@ static int __init coresight_init(void)
ret = etm_perf_init(); if (ret)
bus_unregister(&coresight_bustype);
goto exit_bus_unregister;
/* initialise the coresight syscfg driver and device */
ret = cscfg_driver_init();
if (ret)
goto exit_perf_clear;
ret = cscfg_create_device();
if (!ret)
return 0;
cscfg_driver_exit();
+exit_perf_clear:
etm_perf_exit();
+exit_bus_unregister:
bus_unregister(&coresight_bustype); return ret;
}
static void __exit coresight_exit(void) {
cscfg_clear_device();
cscfg_driver_exit(); etm_perf_exit(); bus_unregister(&coresight_bustype);
} @@ -1700,3 +1726,4 @@ module_exit(coresight_exit); MODULE_AUTHOR("Pratik Patel pratikp@codeaurora.org"); MODULE_AUTHOR("Mathieu Poirier mathieu.poirier@linaro.org"); MODULE_DESCRIPTION("Arm CoreSight tracer driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 668b3ff11576..2d619b764738 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -619,7 +619,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..badef8cfc7f8 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -0,0 +1,136 @@ +// 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-syscfg.h"
+/*
- cs_syscfg device is a virtual device managing the overall cs system.
- It allows the loading of configurations and features, and loads these into
- coresight devices as appropriate.
- */
+static DEFINE_MUTEX(cs_cfg_mutex);
+/* only one of these */ +static struct cs_cfg_device *cscfg_dev;
+static struct device_type cscfg_dev_type = {
.name = "cs_syscfg",
+};
+#define to_device_cscfg() (&cscfg_dev->csdev.dev) +#define to_coresight_device_cscfg() (&cscfg_dev->csdev)
+/* cs_syscfg device instance handling */ +static void cscfg_device_release(struct device *dev) +{
kfree(cscfg_dev->csdev.pdata);
kfree(cscfg_dev);
cscfg_dev = NULL;
+}
+int cscfg_create_device(void) +{
struct device *dev;
struct coresight_device *csdev;
struct coresight_platform_data *pdata = NULL;
int err = -ENOMEM;
mutex_lock(&cs_cfg_mutex);
if (cscfg_dev) {
err = -EINVAL;
goto create_dev_exit_unlock;
}
cscfg_dev = kzalloc(sizeof(*cscfg_dev), GFP_KERNEL);
if (!cscfg_dev)
goto create_dev_exit_unlock;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
kfree(cscfg_dev);
cscfg_dev = NULL;
goto create_dev_exit_unlock;
}
/* setup the device */
dev = to_device_cscfg();
dev_set_name(dev, "cs_syscfg");
dev->bus = &coresight_bustype;
dev->parent = &platform_bus;
dev->type = &cscfg_dev_type;
As far as I can tell setting the device type doesn't do anything.
It provides name for the entry in /sys/devices/... - ie.
/sys/devices/platform/cs_syscfg
The device name is set in dev_set_name(), which is sufficient for proper labelling in sysfs.
/* setup a coresight device */
csdev = to_coresight_device_cscfg();
csdev->type = CORESIGHT_DEV_TYPE_SYSCFG;
csdev->pdata = pdata;
csdev->orphan = false;
csdev->dev.release = cscfg_device_release;
I also fail to understand the requirement to use a coresight_device and to add it to the coresigh bus. To me it seems odd to have it there since it has no interaction with any of the other CS devices.
Not at this early stage - this patch just introduces the device, without much functionality at present. But later on it becomes capable of loading features and configurations and enabling them across relevant devices on the bus.
The bus_type is very rich in feature and should provide everything you need. Using a csdev should be the very last option.
err = device_register(dev);
+create_dev_exit_unlock:
mutex_unlock(&cs_cfg_mutex);
return err;
+}
+void cscfg_clear_device(void) +{
mutex_lock(&cs_cfg_mutex);
device_unregister(to_device_cscfg());
mutex_unlock(&cs_cfg_mutex);
+}
+/* Finish allocating resources and load built-in configurations and features. */ +static int cscfg_probe(struct device *dev) +{
int ret = 0;
/* there can be only one... */
if (dev != to_device_cscfg())
return -EINVAL;
/*
* No actual hardware to handle, just allocate resources.
* Probe is triggered when the core calls cscfg_create_device() to
* create the device, so the mutex is already held.
*/
INIT_LIST_HEAD(&cscfg_dev->dev_list);
INIT_LIST_HEAD(&cscfg_dev->feat_list);
INIT_LIST_HEAD(&cscfg_dev->config_list);
dev_info(dev, "CSCFG initialised");
return ret;
+}
+/* driver initialisation */ +static struct cs_cfg_driver cs_config_driver = {
This set uses cs_cfg_ and cscfg_ to declare structures and function, making it very difficult to read the code. Please pick one (I'd go with the latter but that's a personal opinion) and stick with it.
Agreed - I started off using cs_cfg_.. for data structures, and cscfg_... for functions - but I'll use just the one as it is easier.
I also don't think the functionality provided in this file need to be a driver, it can simply be a set of functions handling configuration and features.
The thinking here was that:-
- a virtual device is a good way of modelling functionality that
affects the entire coresight subsystem - i.e. treat it as a compound device. 2) A device object / kobject is required to support some kernel functionality such as sysfs and configfs when that is added.
That said, my work on configfs - which is not included in this set - would seem to indicate an explicit driver may not be needed, and a set of callback functions and data structures defined in the coresight module may be sufficient. So it may be possible to drop the driver abastaction for now and re-introduce if it does become necessary.
I think that makes sense and will help making this set smaller.
One requirement I didn't spot when dropping the syscfg device is the link into the perf cs_etm event.
I have been working on the perf events part of the set, and found that without an "owner" device we cannot set the configuration information under cs_etm. We cannot use individual csdevs from ETM etc as these can appear / disappear. The 'sinks" names are directly owned by the individual sinks - configurations are system wide so need a system owner.
This means I now have to re-introduce the syscfg coresight device.
Regards
Mike
Thanks for the review
I will continue with patch 3 and 4 today.
Mike
.drv = {
.name = "coresight-syscfg",
.owner = THIS_MODULE,
.suppress_bind_attrs = true,
.probe = cscfg_probe,
},
+};
+/* called from coresight core init */ +int __init cscfg_driver_init(void) +{
cs_config_driver.drv.bus = &coresight_bustype;
return driver_register(&cs_config_driver.drv);
+}
+void cscfg_driver_exit(void) +{
driver_unregister(&cs_config_driver.drv);
+} diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h new file mode 100644 index 000000000000..20ccca5e4151 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -0,0 +1,39 @@ +/* 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>
+/**
- System configuration device.
- @csdev: The coresight device instance.
- @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.
- */
+struct cs_cfg_device {
struct coresight_device csdev;
struct list_head dev_list;
struct list_head feat_list;
struct list_head config_list;
int nr_csdev;
+};
+/* basic device driver */ +struct cs_cfg_driver {
struct device_driver drv;
+};
+/* internal core operations for cscfg */ +int cscfg_create_device(void); +void cscfg_clear_device(void); +int __init cscfg_driver_init(void); +void cscfg_driver_exit(void);
+#endif /* CORESIGHT_SYSCFG_H */ diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 7d3c87e5b97c..ed0a9d938303 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -42,6 +42,7 @@ enum coresight_dev_type { CORESIGHT_DEV_TYPE_SOURCE, CORESIGHT_DEV_TYPE_HELPER, CORESIGHT_DEV_TYPE_ECT,
CORESIGHT_DEV_TYPE_SYSCFG,
};
enum coresight_dev_subtype_sink {
2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
On Thu, Oct 15, 2020 at 11:44:30AM +0100, Mike Leach wrote:
Hi Mathieu,
On Tue, 6 Oct 2020 at 18:31, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Tue, Oct 06, 2020 at 11:40:46AM +0100, Mike Leach wrote:
Hi Mathieu,
On Thu, 1 Oct 2020 at 21:07, Mathieu Poirier mathieu.poirier@linaro.org wrote:
Good afternoon Mike,
On Thu, Aug 27, 2020 at 03:34:04PM +0100, Mike Leach wrote:
Creates a virtual coresight device on the bus to handle system configuration of the coresight infrastructure.
The device 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 updates the coresight core initialisation to create the single instance of the cs_syscfg coresight system device, on the coresight bus.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 2 +- drivers/hwtracing/coresight/coresight-core.c | 29 +++- .../hwtracing/coresight/coresight-etm-perf.c | 2 +- .../hwtracing/coresight/coresight-etm-perf.h | 2 +- .../hwtracing/coresight/coresight-syscfg.c | 136 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 39 +++++ include/linux/coresight.h | 1 + 7 files changed, 207 insertions(+), 4 deletions(-) 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 1b35b55bd420..3605dd770664 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-core.c b/drivers/hwtracing/coresight/coresight-core.c index bf6edf468963..91f1fbd7d51d 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);
@@ -1669,8 +1670,17 @@ char *coresight_alloc_device_name(struct coresight_dev_list *dict, } EXPORT_SYMBOL_GPL(coresight_alloc_device_name);
+/* match for virtual csdevs that have no underlying amba device */ +static int coresight_bus_match(struct device *dev, struct device_driver *drv) +{
struct coresight_device *csdev = to_coresight_device(dev);
return csdev->type == CORESIGHT_DEV_TYPE_SYSCFG;
+}
struct bus_type coresight_bustype = { .name = "coresight",
.match = coresight_bus_match,
};
static int __init coresight_init(void) @@ -1683,13 +1693,29 @@ static int __init coresight_init(void)
ret = etm_perf_init(); if (ret)
bus_unregister(&coresight_bustype);
goto exit_bus_unregister;
/* initialise the coresight syscfg driver and device */
ret = cscfg_driver_init();
if (ret)
goto exit_perf_clear;
ret = cscfg_create_device();
if (!ret)
return 0;
cscfg_driver_exit();
+exit_perf_clear:
etm_perf_exit();
+exit_bus_unregister:
bus_unregister(&coresight_bustype); return ret;
}
static void __exit coresight_exit(void) {
cscfg_clear_device();
cscfg_driver_exit(); etm_perf_exit(); bus_unregister(&coresight_bustype);
} @@ -1700,3 +1726,4 @@ module_exit(coresight_exit); MODULE_AUTHOR("Pratik Patel pratikp@codeaurora.org"); MODULE_AUTHOR("Mathieu Poirier mathieu.poirier@linaro.org"); MODULE_DESCRIPTION("Arm CoreSight tracer driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 668b3ff11576..2d619b764738 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -619,7 +619,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..badef8cfc7f8 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -0,0 +1,136 @@ +// 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-syscfg.h"
+/*
- cs_syscfg device is a virtual device managing the overall cs system.
- It allows the loading of configurations and features, and loads these into
- coresight devices as appropriate.
- */
+static DEFINE_MUTEX(cs_cfg_mutex);
+/* only one of these */ +static struct cs_cfg_device *cscfg_dev;
+static struct device_type cscfg_dev_type = {
.name = "cs_syscfg",
+};
+#define to_device_cscfg() (&cscfg_dev->csdev.dev) +#define to_coresight_device_cscfg() (&cscfg_dev->csdev)
+/* cs_syscfg device instance handling */ +static void cscfg_device_release(struct device *dev) +{
kfree(cscfg_dev->csdev.pdata);
kfree(cscfg_dev);
cscfg_dev = NULL;
+}
+int cscfg_create_device(void) +{
struct device *dev;
struct coresight_device *csdev;
struct coresight_platform_data *pdata = NULL;
int err = -ENOMEM;
mutex_lock(&cs_cfg_mutex);
if (cscfg_dev) {
err = -EINVAL;
goto create_dev_exit_unlock;
}
cscfg_dev = kzalloc(sizeof(*cscfg_dev), GFP_KERNEL);
if (!cscfg_dev)
goto create_dev_exit_unlock;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
kfree(cscfg_dev);
cscfg_dev = NULL;
goto create_dev_exit_unlock;
}
/* setup the device */
dev = to_device_cscfg();
dev_set_name(dev, "cs_syscfg");
dev->bus = &coresight_bustype;
dev->parent = &platform_bus;
dev->type = &cscfg_dev_type;
As far as I can tell setting the device type doesn't do anything.
It provides name for the entry in /sys/devices/... - ie.
/sys/devices/platform/cs_syscfg
The device name is set in dev_set_name(), which is sufficient for proper labelling in sysfs.
/* setup a coresight device */
csdev = to_coresight_device_cscfg();
csdev->type = CORESIGHT_DEV_TYPE_SYSCFG;
csdev->pdata = pdata;
csdev->orphan = false;
csdev->dev.release = cscfg_device_release;
I also fail to understand the requirement to use a coresight_device and to add it to the coresigh bus. To me it seems odd to have it there since it has no interaction with any of the other CS devices.
Not at this early stage - this patch just introduces the device, without much functionality at present. But later on it becomes capable of loading features and configurations and enabling them across relevant devices on the bus.
The bus_type is very rich in feature and should provide everything you need. Using a csdev should be the very last option.
err = device_register(dev);
+create_dev_exit_unlock:
mutex_unlock(&cs_cfg_mutex);
return err;
+}
+void cscfg_clear_device(void) +{
mutex_lock(&cs_cfg_mutex);
device_unregister(to_device_cscfg());
mutex_unlock(&cs_cfg_mutex);
+}
+/* Finish allocating resources and load built-in configurations and features. */ +static int cscfg_probe(struct device *dev) +{
int ret = 0;
/* there can be only one... */
if (dev != to_device_cscfg())
return -EINVAL;
/*
* No actual hardware to handle, just allocate resources.
* Probe is triggered when the core calls cscfg_create_device() to
* create the device, so the mutex is already held.
*/
INIT_LIST_HEAD(&cscfg_dev->dev_list);
INIT_LIST_HEAD(&cscfg_dev->feat_list);
INIT_LIST_HEAD(&cscfg_dev->config_list);
dev_info(dev, "CSCFG initialised");
return ret;
+}
+/* driver initialisation */ +static struct cs_cfg_driver cs_config_driver = {
This set uses cs_cfg_ and cscfg_ to declare structures and function, making it very difficult to read the code. Please pick one (I'd go with the latter but that's a personal opinion) and stick with it.
Agreed - I started off using cs_cfg_.. for data structures, and cscfg_... for functions - but I'll use just the one as it is easier.
I also don't think the functionality provided in this file need to be a driver, it can simply be a set of functions handling configuration and features.
The thinking here was that:-
- a virtual device is a good way of modelling functionality that
affects the entire coresight subsystem - i.e. treat it as a compound device. 2) A device object / kobject is required to support some kernel functionality such as sysfs and configfs when that is added.
That said, my work on configfs - which is not included in this set - would seem to indicate an explicit driver may not be needed, and a set of callback functions and data structures defined in the coresight module may be sufficient. So it may be possible to drop the driver abastaction for now and re-introduce if it does become necessary.
I think that makes sense and will help making this set smaller.
One requirement I didn't spot when dropping the syscfg device is the link into the perf cs_etm event.
I have been working on the perf events part of the set, and found that without an "owner" device we cannot set the configuration information under cs_etm. We cannot use individual csdevs from ETM etc as these can appear / disappear. The 'sinks" names are directly owned by the individual sinks - configurations are system wide so need a system owner.
This means I now have to re-introduce the syscfg coresight device.
You are correct - working with sysfs means that a device has to be involved. But it doesn't have to be a csdev and doesn't have to be added to the CS bus either. As far as I can see in this set the csdev itself isn't used but the device associated to the csdev is.
Regards
Mike
Thanks for the review
I will continue with patch 3 and 4 today.
Mike
.drv = {
.name = "coresight-syscfg",
.owner = THIS_MODULE,
.suppress_bind_attrs = true,
.probe = cscfg_probe,
},
+};
+/* called from coresight core init */ +int __init cscfg_driver_init(void) +{
cs_config_driver.drv.bus = &coresight_bustype;
return driver_register(&cs_config_driver.drv);
+}
+void cscfg_driver_exit(void) +{
driver_unregister(&cs_config_driver.drv);
+} diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h new file mode 100644 index 000000000000..20ccca5e4151 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -0,0 +1,39 @@ +/* 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>
+/**
- System configuration device.
- @csdev: The coresight device instance.
- @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.
- */
+struct cs_cfg_device {
struct coresight_device csdev;
struct list_head dev_list;
struct list_head feat_list;
struct list_head config_list;
int nr_csdev;
+};
+/* basic device driver */ +struct cs_cfg_driver {
struct device_driver drv;
+};
+/* internal core operations for cscfg */ +int cscfg_create_device(void); +void cscfg_clear_device(void); +int __init cscfg_driver_init(void); +void cscfg_driver_exit(void);
+#endif /* CORESIGHT_SYSCFG_H */ diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 7d3c87e5b97c..ed0a9d938303 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -42,6 +42,7 @@ enum coresight_dev_type { CORESIGHT_DEV_TYPE_SOURCE, CORESIGHT_DEV_TYPE_HELPER, CORESIGHT_DEV_TYPE_ECT,
CORESIGHT_DEV_TYPE_SYSCFG,
};
enum coresight_dev_subtype_sink {
2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
Add API call to load features and configurations into the system lists.
Defines generic structures and flags needed to describe features and configurations.
Signed-off-by: Mike Leach mike.leach@linaro.org --- .../hwtracing/coresight/coresight-config.h | 154 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.c | 116 +++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 26 +++ 3 files changed, 296 insertions(+) create mode 100644 drivers/hwtracing/coresight/coresight-config.h
diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h new file mode 100644 index 000000000000..413509f7d817 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -0,0 +1,154 @@ +/* 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 */ +#define CS_CFG_CONFIG_PRESET_MAX 15 + + +/** + * Parameter descriptor for a device feature. + * + * @name: Name of parameter. + * @value: Initial or default value. + */ +struct cs_cfg_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. + */ +union cs_cfg_regval { + u64 val64; + struct { + u32 val32; + u32 mask32; + }; +}; + +/** + * Register descriptor for a device feature. + * Flags define 32bit, 32bit+mask, 64bit. + * + * @flags: flags defining the handling of the register. + * @value: Initial value & optional mask. + */ +struct cs_cfg_reg_desc { + u32 flags; + union cs_cfg_regval value; +}; + +/** + * 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. + * @match_flags: matching information if loading into a device + * @params: list of parameters used - 0 terminated. + * @reg: list of registers used. + */ +struct cs_cfg_feature_desc { + const char *name; + const char *brief; + u32 match_flags; + struct cs_cfg_parameter_desc *params; + struct cs_cfg_reg_desc *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. + * + */ +struct cs_cfg_match_info { + u32 flags; /* match flags */ + /* unique device name (e.g. amba bus name) for specific device match */ + const char *dev_name; +}; + +/** + * Uses feature description. + * + * @name: name of feature to use. + * @nr_params: number of parameters the feature has. + * @match: match info for the feature in use - may be all devices of a + * class or a specific device in that class. + */ +struct cs_cfg_uses_feat_desc { + const char *name; + int nr_params; + struct cs_cfg_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. + * @nr_uses: Number of features used in this configuration. + * @used: feature use descriptors. + * @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 cs_cfg_config_desc { + const char *name; + const char *brief; + int nr_uses; + struct cs_cfg_uses_feat_desc *uses; + 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-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index badef8cfc7f8..d49bcace76c8 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -6,6 +6,7 @@
#include <linux/platform_device.h>
+#include "coresight-config.h" #include "coresight-syscfg.h"
@@ -28,6 +29,121 @@ static struct device_type cscfg_dev_type = { #define to_device_cscfg() (&cscfg_dev->csdev.dev) #define to_coresight_device_cscfg() (&cscfg_dev->csdev)
+/* 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_featlist_item *curr_item; + + list_for_each_entry(curr_item, &cscfg_dev->feat_list, item) { + if (strcmp(curr_item->desc->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 cs_cfg_config_desc *cfg_desc) +{ + int i; + + for (i = 0; i < cfg_desc->nr_uses; i++) + if (!cscfg_match_list_feat(cfg_desc->uses[i].name)) + return -EINVAL; + return 0; +} + +/* + * load feature - add to feature list. + */ +static int cscfg_load_feat(struct cs_cfg_feature_desc *feat_desc) +{ + struct cscfg_featlist_item *feat_item; + + if (!cscfg_dev) + return -ENODEV; + + /* create a list item and add to the list */ + feat_item = devm_kzalloc(to_device_cscfg(), + sizeof(struct cscfg_featlist_item), + GFP_KERNEL); + if (!feat_item) + return -ENOMEM; + + feat_item->desc = feat_desc; + list_add(&feat_item->item, &cscfg_dev->feat_list); + + return 0; +} + +/* + * load config into the system - validate used features exist then add to + * config list. + */ +static int cscfg_load_config(struct cs_cfg_config_desc *cfg_desc) +{ + int err = -ENODEV; + struct cs_cfg_config *cfg; + + if (!cscfg_dev) + return -ENODEV; + + /* validate features are present */ + err = cscfg_check_feat_for_cfg(cfg_desc); + if (err) + return err; + + /* add to list */ + cfg = devm_kzalloc(to_device_cscfg(), + sizeof(struct cs_cfg_config), GFP_KERNEL); + if (!cfg) + return -ENOMEM; + cfg->desc = cfg_desc; + + list_add(&cfg->item, &cscfg_dev->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 cs_cfg_config_desc **cfg_descs, + struct cs_cfg_feature_desc **feat_descs) +{ + int err, i = 0; + + mutex_lock(&cs_cfg_mutex); + + /* load features first */ + if (feat_descs) { + while (feat_descs[i]) { + err = cscfg_load_feat(feat_descs[i]); + if (err) + return err; + 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) + return err; + i++; + } + } + + mutex_unlock(&cs_cfg_mutex); + return err; +} +EXPORT_SYMBOL_GPL(cscfg_load_config_sets);
/* cs_syscfg device instance handling */ static void cscfg_device_release(struct device *dev) diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 20ccca5e4151..b3d41096382d 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -30,10 +30,36 @@ struct cs_cfg_driver { struct device_driver drv; };
+/** + * List entry for feature loaded into the system feature list. + * + * @desc: Descriptor for the feature. + * @item: List entry + */ +struct cscfg_featlist_item { + const struct cs_cfg_feature_desc *desc; + struct list_head item; +}; + +/** + * List entry for configuration added to system config list. + * + * @desc: Descriptor for the configuration. + * @item: List entry. + */ +struct cs_cfg_config { + const struct cs_cfg_config_desc *desc; + struct list_head item; +}; + /* internal core operations for cscfg */ int cscfg_create_device(void); void cscfg_clear_device(void); int __init cscfg_driver_init(void); void cscfg_driver_exit(void);
+/* syscfg external API */ +int cscfg_load_config_sets(struct cs_cfg_config_desc **cfg_descs, + struct cs_cfg_feature_desc **feat_descs); + #endif /* CORESIGHT_SYSCFG_H */
On Thu, Aug 27, 2020 at 03:34:05PM +0100, Mike Leach wrote:
Add API call to load features and configurations into the system lists.
Defines generic structures and flags needed to describe features and configurations.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-config.h | 154 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.c | 116 +++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 26 +++ 3 files changed, 296 insertions(+) create mode 100644 drivers/hwtracing/coresight/coresight-config.h
diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h new file mode 100644 index 000000000000..413509f7d817 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -0,0 +1,154 @@ +/* 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 */ +#define CS_CFG_CONFIG_PRESET_MAX 15
Any reason to set the maximum number of presets at 15? Could it be a list to be more flexible?
+/**
- Parameter descriptor for a device feature.
- @name: Name of parameter.
- @value: Initial or default value.
- */
+struct cs_cfg_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.
- */
+union cs_cfg_regval {
- u64 val64;
- struct {
u32 val32;
u32 mask32;
- };
+};
+/**
- Register descriptor for a device feature.
- Flags define 32bit, 32bit+mask, 64bit.
- @flags: flags defining the handling of the register.
- @value: Initial value & optional mask.
- */
The initial values of registers could be sufficient to work with a feature - is my understanding correct?
+struct cs_cfg_reg_desc {
- u32 flags;
- union cs_cfg_regval value;
+};
Is this structure absolutely required? Can @flag be added to cs_cfg_regval to avoid the declaration of a new structure?
+/**
- 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.
- @match_flags: matching information if loading into a device
- @params: list of parameters used - 0 terminated.
- @reg: list of registers used.
- */
+struct cs_cfg_feature_desc {
I suggest calling this cs_cfg_feature. That way we can rename cs_cfg_uses_feat_desc to cs_cfg_feature_desc and drop the "uses" part.
- const char *name;
- const char *brief;
- u32 match_flags;
- struct cs_cfg_parameter_desc *params;
- struct cs_cfg_reg_desc *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.
- */
+struct cs_cfg_match_info {
- u32 flags; /* match flags */
Please use "flags" or "match_flags" but not both.
- /* unique device name (e.g. amba bus name) for specific device match */
- const char *dev_name;
+};
+/**
- Uses feature description.
- @name: name of feature to use.
- @nr_params: number of parameters the feature has.
- @match: match info for the feature in use - may be all devices of a
class or a specific device in that class.
- */
+struct cs_cfg_uses_feat_desc {
- const char *name;
If I remember correctly @name needs to match with cs_cfg_feature_desc::name. If that is the case please add a comment to explicitly link them. That will make it easier for people to make the connection.
- int nr_params;
Shouldn't this be defined in cs_cfg_feature_desc?
- struct cs_cfg_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.
- @nr_uses: Number of features used in this configuration.
- @used: feature use descriptors.
- @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 cs_cfg_config_desc {
- const char *name;
- const char *brief;
- int nr_uses;
s/nr_uses/nr_feature_desc
- struct cs_cfg_uses_feat_desc *uses;
s/cs_cfg_uses_feat_desc *uses/cs_cfg_feature_desc *feature_desc
- int nr_presets;
- int nr_total_params;
- const u64 *presets; /* nr_presets * nr_total_params */
What is the difference between presets and the values held by cs_cfg_parameter_desc? Can we get rid of the latter?
+};
+#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index badef8cfc7f8..d49bcace76c8 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -6,6 +6,7 @@ #include <linux/platform_device.h> +#include "coresight-config.h" #include "coresight-syscfg.h" @@ -28,6 +29,121 @@ static struct device_type cscfg_dev_type = { #define to_device_cscfg() (&cscfg_dev->csdev.dev) #define to_coresight_device_cscfg() (&cscfg_dev->csdev) +/* 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_featlist_item *curr_item;
- list_for_each_entry(curr_item, &cscfg_dev->feat_list, item) {
if (strcmp(curr_item->desc->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 cs_cfg_config_desc *cfg_desc) +{
- int i;
- for (i = 0; i < cfg_desc->nr_uses; i++)
if (!cscfg_match_list_feat(cfg_desc->uses[i].name))
return -EINVAL;
- return 0;
+}
+/*
- load feature - add to feature list.
- */
+static int cscfg_load_feat(struct cs_cfg_feature_desc *feat_desc) +{
- struct cscfg_featlist_item *feat_item;
- if (!cscfg_dev)
return -ENODEV;
- /* create a list item and add to the list */
- feat_item = devm_kzalloc(to_device_cscfg(),
sizeof(struct cscfg_featlist_item),
GFP_KERNEL);
- if (!feat_item)
return -ENOMEM;
- feat_item->desc = feat_desc;
- list_add(&feat_item->item, &cscfg_dev->feat_list);
- return 0;
+}
+/*
- load config into the system - validate used features exist then add to
- config list.
- */
+static int cscfg_load_config(struct cs_cfg_config_desc *cfg_desc) +{
- int err = -ENODEV;
- struct cs_cfg_config *cfg;
- if (!cscfg_dev)
return -ENODEV;
- /* validate features are present */
- err = cscfg_check_feat_for_cfg(cfg_desc);
- if (err)
return err;
- /* add to list */
- cfg = devm_kzalloc(to_device_cscfg(),
sizeof(struct cs_cfg_config), GFP_KERNEL);
- if (!cfg)
return -ENOMEM;
- cfg->desc = cfg_desc;
- list_add(&cfg->item, &cscfg_dev->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 cs_cfg_config_desc **cfg_descs,
struct cs_cfg_feature_desc **feat_descs)
+{
- int err, i = 0;
- mutex_lock(&cs_cfg_mutex);
- /* load features first */
- if (feat_descs) {
while (feat_descs[i]) {
err = cscfg_load_feat(feat_descs[i]);
if (err)
return err;
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)
return err;
i++;
}
- }
Features and configurations aren't unloaded when an error occurs. That is probably something that could go in csfg_device_release().
- mutex_unlock(&cs_cfg_mutex);
- return err;
+} +EXPORT_SYMBOL_GPL(cscfg_load_config_sets); /* cs_syscfg device instance handling */ static void cscfg_device_release(struct device *dev) diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 20ccca5e4151..b3d41096382d 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -30,10 +30,36 @@ struct cs_cfg_driver { struct device_driver drv; }; +/**
- List entry for feature loaded into the system feature list.
- @desc: Descriptor for the feature.
- @item: List entry
- */
+struct cscfg_featlist_item {
- const struct cs_cfg_feature_desc *desc;
- struct list_head item;
+};
I would add the list_head to structure cs_cfg_feature_desc and get rid of cscfg_featlist_item.
+/**
- List entry for configuration added to system config list.
- @desc: Descriptor for the configuration.
- @item: List entry.
- */
+struct cs_cfg_config {
- const struct cs_cfg_config_desc *desc;
- struct list_head item;
+};
Same as above.
/* internal core operations for cscfg */ int cscfg_create_device(void); void cscfg_clear_device(void); int __init cscfg_driver_init(void); void cscfg_driver_exit(void); +/* syscfg external API */ +int cscfg_load_config_sets(struct cs_cfg_config_desc **cfg_descs,
struct cs_cfg_feature_desc **feat_descs);
#endif /* CORESIGHT_SYSCFG_H */
2.17.1
Hi Mathieu,
On Thu, 1 Oct 2020 at 22:20, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Thu, Aug 27, 2020 at 03:34:05PM +0100, Mike Leach wrote:
Add API call to load features and configurations into the system lists.
Defines generic structures and flags needed to describe features and configurations.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-config.h | 154 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.c | 116 +++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 26 +++ 3 files changed, 296 insertions(+) create mode 100644 drivers/hwtracing/coresight/coresight-config.h
diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h new file mode 100644 index 000000000000..413509f7d817 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -0,0 +1,154 @@ +/* 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 */ +#define CS_CFG_CONFIG_PRESET_MAX 15
Any reason to set the maximum number of presets at 15? Could it be a list to be more flexible?
This is linked to the number of bits (4) used to select presets in the perf config2 value, introduced later in the perf updates. We can certainly increase the number of bits ./ max entries - but this seems like a reasonable starting point.
+/**
- Parameter descriptor for a device feature.
- @name: Name of parameter.
- @value: Initial or default value.
- */
+struct cs_cfg_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.
- */
+union cs_cfg_regval {
u64 val64;
struct {
u32 val32;
u32 mask32;
};
+};
+/**
- Register descriptor for a device feature.
- Flags define 32bit, 32bit+mask, 64bit.
- @flags: flags defining the handling of the register.
- @value: Initial value & optional mask.
- */
The initial values of registers could be sufficient to work with a feature - is my understanding correct?
Correct. Values in the description of the feature form the defaults for programming the device. These can be absolute values - which are used directly, resource values - where the loading process will select an appropriate resource (e.g. etm counter), or parameter value, which has a default value that can be updated at runtime via sysfs / configfs.
+struct cs_cfg_reg_desc {
u32 flags;
union cs_cfg_regval value;
+};
Is this structure absolutely required? Can @flag be added to cs_cfg_regval to avoid the declaration of a new structure?
The structures are split into 'descriptors' - which describe a feature / configuration and 'instances' which represent the feature loaded into a specific device. So in a system with 4 ETMv4 , a single feature descriptor for ETMv4, will result in 4 instances loaded into the respective ETM devices. The reg_val appears in both.
That said, for simplification purposes, we could move the flags into the value and drop this structure at the cost of a very marginal memory increase.
+/**
- 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.
- @match_flags: matching information if loading into a device
- @params: list of parameters used - 0 terminated.
- @reg: list of registers used.
- */
+struct cs_cfg_feature_desc {
I suggest calling this cs_cfg_feature. That way we can rename cs_cfg_uses_feat_desc to cs_cfg_feature_desc and drop the "uses" part.
cs_cfg_feature exists as the structure used for the instance of a feature loaded into a device, introduced in a later patch.
const char *name;
const char *brief;
u32 match_flags;
struct cs_cfg_parameter_desc *params;
struct cs_cfg_reg_desc *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.
- */
+struct cs_cfg_match_info {
u32 flags; /* match flags */
Please use "flags" or "match_flags" but not both.
Will do.
/* unique device name (e.g. amba bus name) for specific device match */
const char *dev_name;
+};
+/**
- Uses feature description.
- @name: name of feature to use.
- @nr_params: number of parameters the feature has.
- @match: match info for the feature in use - may be all devices of a
class or a specific device in that class.
- */
+struct cs_cfg_uses_feat_desc {
const char *name;
If I remember correctly @name needs to match with cs_cfg_feature_desc::name. If that is the case please add a comment to explicitly link them. That will make it easier for people to make the connection.
will do.
int nr_params;
Shouldn't this be defined in cs_cfg_feature_desc?
yes - that would be better.
struct cs_cfg_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.
- @nr_uses: Number of features used in this configuration.
- @used: feature use descriptors.
- @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 cs_cfg_config_desc {
const char *name;
const char *brief;
int nr_uses;
s/nr_uses/nr_feature_desc
struct cs_cfg_uses_feat_desc *uses;
s/cs_cfg_uses_feat_desc *uses/cs_cfg_feature_desc *feature_desc
int nr_presets;
int nr_total_params;
const u64 *presets; /* nr_presets * nr_total_params */
What is the difference between presets and the values held by cs_cfg_parameter_desc? Can we get rid of the latter?
The cs_cfg_parameter_desc represent the default parameter values for the feature - which can be loaded / used independently of a configuration that provides presets.
+};
+#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index badef8cfc7f8..d49bcace76c8 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -6,6 +6,7 @@
#include <linux/platform_device.h>
+#include "coresight-config.h" #include "coresight-syscfg.h"
@@ -28,6 +29,121 @@ static struct device_type cscfg_dev_type = { #define to_device_cscfg() (&cscfg_dev->csdev.dev) #define to_coresight_device_cscfg() (&cscfg_dev->csdev)
+/* 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_featlist_item *curr_item;
list_for_each_entry(curr_item, &cscfg_dev->feat_list, item) {
if (strcmp(curr_item->desc->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 cs_cfg_config_desc *cfg_desc) +{
int i;
for (i = 0; i < cfg_desc->nr_uses; i++)
if (!cscfg_match_list_feat(cfg_desc->uses[i].name))
return -EINVAL;
return 0;
+}
+/*
- load feature - add to feature list.
- */
+static int cscfg_load_feat(struct cs_cfg_feature_desc *feat_desc) +{
struct cscfg_featlist_item *feat_item;
if (!cscfg_dev)
return -ENODEV;
/* create a list item and add to the list */
feat_item = devm_kzalloc(to_device_cscfg(),
sizeof(struct cscfg_featlist_item),
GFP_KERNEL);
if (!feat_item)
return -ENOMEM;
feat_item->desc = feat_desc;
list_add(&feat_item->item, &cscfg_dev->feat_list);
return 0;
+}
+/*
- load config into the system - validate used features exist then add to
- config list.
- */
+static int cscfg_load_config(struct cs_cfg_config_desc *cfg_desc) +{
int err = -ENODEV;
struct cs_cfg_config *cfg;
if (!cscfg_dev)
return -ENODEV;
/* validate features are present */
err = cscfg_check_feat_for_cfg(cfg_desc);
if (err)
return err;
/* add to list */
cfg = devm_kzalloc(to_device_cscfg(),
sizeof(struct cs_cfg_config), GFP_KERNEL);
if (!cfg)
return -ENOMEM;
cfg->desc = cfg_desc;
list_add(&cfg->item, &cscfg_dev->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 cs_cfg_config_desc **cfg_descs,
struct cs_cfg_feature_desc **feat_descs)
+{
int err, i = 0;
mutex_lock(&cs_cfg_mutex);
/* load features first */
if (feat_descs) {
while (feat_descs[i]) {
err = cscfg_load_feat(feat_descs[i]);
if (err)
return err;
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)
return err;
i++;
}
}
Features and configurations aren't unloaded when an error occurs. That is probably something that could go in csfg_device_release().
At present, configurations & features can only be loaded via the built-in block of code. This really shouldn't have errors - but we should probably have a least a message here.. The error handling is broken as has been pointed out in Yabin's mail.
Once dynamic loading is permitted - either by loadable module or though the configfs - the handing of unload will be added. For a given set, failing to load a configuration does not necessarily invalidate the previous features, which can be used directly or in other configurations. At present the memory associated with loading configurations and features into the device is allocate using the devm_ allocators associated with the virtual syscfg device - and thus is correctly cleaned up.
mutex_unlock(&cs_cfg_mutex);
return err;
+} +EXPORT_SYMBOL_GPL(cscfg_load_config_sets);
/* cs_syscfg device instance handling */ static void cscfg_device_release(struct device *dev) diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 20ccca5e4151..b3d41096382d 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -30,10 +30,36 @@ struct cs_cfg_driver { struct device_driver drv; };
+/**
- List entry for feature loaded into the system feature list.
- @desc: Descriptor for the feature.
- @item: List entry
- */
+struct cscfg_featlist_item {
const struct cs_cfg_feature_desc *desc;
struct list_head item;
+};
I would add the list_head to structure cs_cfg_feature_desc and get rid of cscfg_featlist_item.
agreed.
+/**
- List entry for configuration added to system config list.
- @desc: Descriptor for the configuration.
- @item: List entry.
- */
+struct cs_cfg_config {
const struct cs_cfg_config_desc *desc;
struct list_head item;
+};
Same as above.
agreed.
/* internal core operations for cscfg */ int cscfg_create_device(void); void cscfg_clear_device(void); int __init cscfg_driver_init(void); void cscfg_driver_exit(void);
+/* syscfg external API */ +int cscfg_load_config_sets(struct cs_cfg_config_desc **cfg_descs,
struct cs_cfg_feature_desc **feat_descs);
#endif /* CORESIGHT_SYSCFG_H */
2.17.1
Thanks for the review
Regards
Mike
On Tue, Oct 06, 2020 at 12:18:51PM +0100, Mike Leach wrote:
Hi Mathieu,
On Thu, 1 Oct 2020 at 22:20, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Thu, Aug 27, 2020 at 03:34:05PM +0100, Mike Leach wrote:
Add API call to load features and configurations into the system lists.
Defines generic structures and flags needed to describe features and configurations.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-config.h | 154 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.c | 116 +++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 26 +++ 3 files changed, 296 insertions(+) create mode 100644 drivers/hwtracing/coresight/coresight-config.h
diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h new file mode 100644 index 000000000000..413509f7d817 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -0,0 +1,154 @@ +/* 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 */ +#define CS_CFG_CONFIG_PRESET_MAX 15
Any reason to set the maximum number of presets at 15? Could it be a list to be more flexible?
This is linked to the number of bits (4) used to select presets in the perf config2 value, introduced later in the perf updates. We can certainly increase the number of bits ./ max entries - but this seems like a reasonable starting point.
Oh boy - the relation with the 4 bits in config2 was completely lost on me. Adding a comment to clearly identify the link between the two would go a long way.
That being said I remember frowning a little when I looked at how config2 was used and something I will pay close attention to in this second pass.
+/**
- Parameter descriptor for a device feature.
- @name: Name of parameter.
- @value: Initial or default value.
- */
+struct cs_cfg_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.
- */
+union cs_cfg_regval {
u64 val64;
struct {
u32 val32;
u32 mask32;
};
+};
+/**
- Register descriptor for a device feature.
- Flags define 32bit, 32bit+mask, 64bit.
- @flags: flags defining the handling of the register.
- @value: Initial value & optional mask.
- */
The initial values of registers could be sufficient to work with a feature - is my understanding correct?
Correct. Values in the description of the feature form the defaults for programming the device. These can be absolute values - which are used directly, resource values - where the loading process will select an appropriate resource (e.g. etm counter), or parameter value, which has a default value that can be updated at runtime via sysfs / configfs.
+struct cs_cfg_reg_desc {
u32 flags;
union cs_cfg_regval value;
+};
Is this structure absolutely required? Can @flag be added to cs_cfg_regval to avoid the declaration of a new structure?
The structures are split into 'descriptors' - which describe a feature / configuration and 'instances' which represent the feature loaded into a specific device. So in a system with 4 ETMv4 , a single feature descriptor for ETMv4, will result in 4 instances loaded into the respective ETM devices. The reg_val appears in both.
That said, for simplification purposes, we could move the flags into the value and drop this structure at the cost of a very marginal memory increase.
Thanks
+/**
- 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.
- @match_flags: matching information if loading into a device
- @params: list of parameters used - 0 terminated.
- @reg: list of registers used.
- */
+struct cs_cfg_feature_desc {
I suggest calling this cs_cfg_feature. That way we can rename cs_cfg_uses_feat_desc to cs_cfg_feature_desc and drop the "uses" part.
cs_cfg_feature exists as the structure used for the instance of a feature loaded into a device, introduced in a later patch.
My goal is to find a different label than "uses". It took me a while wrap my head around it and even after that I kept tripping on it.
Maybe keep it as it is for now and we can revisit as this set matures.
const char *name;
const char *brief;
u32 match_flags;
struct cs_cfg_parameter_desc *params;
struct cs_cfg_reg_desc *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.
- */
+struct cs_cfg_match_info {
u32 flags; /* match flags */
Please use "flags" or "match_flags" but not both.
Will do.
/* unique device name (e.g. amba bus name) for specific device match */
const char *dev_name;
+};
+/**
- Uses feature description.
- @name: name of feature to use.
- @nr_params: number of parameters the feature has.
- @match: match info for the feature in use - may be all devices of a
class or a specific device in that class.
- */
+struct cs_cfg_uses_feat_desc {
const char *name;
If I remember correctly @name needs to match with cs_cfg_feature_desc::name. If that is the case please add a comment to explicitly link them. That will make it easier for people to make the connection.
will do.
int nr_params;
Shouldn't this be defined in cs_cfg_feature_desc?
yes - that would be better.
struct cs_cfg_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.
- @nr_uses: Number of features used in this configuration.
- @used: feature use descriptors.
- @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 cs_cfg_config_desc {
const char *name;
const char *brief;
int nr_uses;
s/nr_uses/nr_feature_desc
struct cs_cfg_uses_feat_desc *uses;
s/cs_cfg_uses_feat_desc *uses/cs_cfg_feature_desc *feature_desc
int nr_presets;
int nr_total_params;
const u64 *presets; /* nr_presets * nr_total_params */
What is the difference between presets and the values held by cs_cfg_parameter_desc? Can we get rid of the latter?
The cs_cfg_parameter_desc represent the default parameter values for the feature - which can be loaded / used independently of a configuration that provides presets.
+};
+#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index badef8cfc7f8..d49bcace76c8 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -6,6 +6,7 @@
#include <linux/platform_device.h>
+#include "coresight-config.h" #include "coresight-syscfg.h"
@@ -28,6 +29,121 @@ static struct device_type cscfg_dev_type = { #define to_device_cscfg() (&cscfg_dev->csdev.dev) #define to_coresight_device_cscfg() (&cscfg_dev->csdev)
+/* 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_featlist_item *curr_item;
list_for_each_entry(curr_item, &cscfg_dev->feat_list, item) {
if (strcmp(curr_item->desc->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 cs_cfg_config_desc *cfg_desc) +{
int i;
for (i = 0; i < cfg_desc->nr_uses; i++)
if (!cscfg_match_list_feat(cfg_desc->uses[i].name))
return -EINVAL;
return 0;
+}
+/*
- load feature - add to feature list.
- */
+static int cscfg_load_feat(struct cs_cfg_feature_desc *feat_desc) +{
struct cscfg_featlist_item *feat_item;
if (!cscfg_dev)
return -ENODEV;
/* create a list item and add to the list */
feat_item = devm_kzalloc(to_device_cscfg(),
sizeof(struct cscfg_featlist_item),
GFP_KERNEL);
if (!feat_item)
return -ENOMEM;
feat_item->desc = feat_desc;
list_add(&feat_item->item, &cscfg_dev->feat_list);
return 0;
+}
+/*
- load config into the system - validate used features exist then add to
- config list.
- */
+static int cscfg_load_config(struct cs_cfg_config_desc *cfg_desc) +{
int err = -ENODEV;
struct cs_cfg_config *cfg;
if (!cscfg_dev)
return -ENODEV;
/* validate features are present */
err = cscfg_check_feat_for_cfg(cfg_desc);
if (err)
return err;
/* add to list */
cfg = devm_kzalloc(to_device_cscfg(),
sizeof(struct cs_cfg_config), GFP_KERNEL);
if (!cfg)
return -ENOMEM;
cfg->desc = cfg_desc;
list_add(&cfg->item, &cscfg_dev->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 cs_cfg_config_desc **cfg_descs,
struct cs_cfg_feature_desc **feat_descs)
+{
int err, i = 0;
mutex_lock(&cs_cfg_mutex);
/* load features first */
if (feat_descs) {
while (feat_descs[i]) {
err = cscfg_load_feat(feat_descs[i]);
if (err)
return err;
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)
return err;
i++;
}
}
Features and configurations aren't unloaded when an error occurs. That is probably something that could go in csfg_device_release().
At present, configurations & features can only be loaded via the built-in block of code. This really shouldn't have errors - but we should probably have a least a message here.. The error handling is broken as has been pointed out in Yabin's mail.
Ok
Once dynamic loading is permitted - either by loadable module or though the configfs - the handing of unload will be added. For a given set, failing to load a configuration does not necessarily invalidate the previous features, which can be used directly or in other configurations. At present the memory associated with loading configurations and features into the device is allocate using the devm_ allocators associated with the virtual syscfg device - and thus is correctly cleaned up.
mutex_unlock(&cs_cfg_mutex);
return err;
+} +EXPORT_SYMBOL_GPL(cscfg_load_config_sets);
/* cs_syscfg device instance handling */ static void cscfg_device_release(struct device *dev) diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 20ccca5e4151..b3d41096382d 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -30,10 +30,36 @@ struct cs_cfg_driver { struct device_driver drv; };
+/**
- List entry for feature loaded into the system feature list.
- @desc: Descriptor for the feature.
- @item: List entry
- */
+struct cscfg_featlist_item {
const struct cs_cfg_feature_desc *desc;
struct list_head item;
+};
I would add the list_head to structure cs_cfg_feature_desc and get rid of cscfg_featlist_item.
agreed.
+/**
- List entry for configuration added to system config list.
- @desc: Descriptor for the configuration.
- @item: List entry.
- */
+struct cs_cfg_config {
const struct cs_cfg_config_desc *desc;
struct list_head item;
+};
Same as above.
agreed.
/* internal core operations for cscfg */ int cscfg_create_device(void); void cscfg_clear_device(void); int __init cscfg_driver_init(void); void cscfg_driver_exit(void);
+/* syscfg external API */ +int cscfg_load_config_sets(struct cs_cfg_config_desc **cfg_descs,
struct cs_cfg_feature_desc **feat_descs);
#endif /* CORESIGHT_SYSCFG_H */
2.17.1
Thanks for the review
Regards
Mike
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
API for individual devices to register with the cs_syscfg driver 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 | 119 ++++++++ .../hwtracing/coresight/coresight-syscfg.c | 268 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 22 ++ include/linux/coresight.h | 7 + 4 files changed, 416 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 413509f7d817..949a078c4692 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -151,4 +151,123 @@ struct cs_cfg_config_desc { const u64 *presets; /* nr_presets * nr_total_params */ };
+/** + * config register instance - part of a loaded feature. + * maps register values to 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 cs_cfg_reg { + union cs_cfg_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 cs_cfg_parameter { + struct cs_cfg_feature *feat; + struct cs_cfg_reg *reg; + u64 current_value; + bool val64; +}; + +/** + * cs_cfg_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 cs_cfg_feat_ops { + int (*set_on_enable)(struct cs_cfg_feature *feat, const bool force_set); + void (*save_on_disable)(struct cs_cfg_feature *feat, const bool force_save); + void (*reset)(struct cs_cfg_feature *feat); +}; + +/** + * Feature instance loaded into a CoreSight device driver. + * + * 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 (@dev_spinlock). + * + * @desc: pointer to the static descriptor for this feature. + * @csdev: parent CoreSight device instance. + * @node: list entry into feature list for this device. + * @dev_spinlock: device spinlock.. + * @enabled: feature is enabled on this device. + * @nr_params: number of parameters. + * @params: current parameter values on this device + * @param_group: sysfs group for feature parameters. + * @ops: standard ops to enable and disable features on devices. + */ +struct cs_cfg_feature { + const struct cs_cfg_feature_desc *desc; + struct coresight_device *csdev; + struct list_head node; + spinlock_t *dev_spinlock; + bool enabled; + int nr_params; + struct cs_cfg_parameter *params; + struct attribute_group *param_group; + int nr_regs; + struct cs_cfg_reg *regs; + struct cs_cfg_feat_ops ops; +}; + +/** + * Configuration instance when loaded into a 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 cs_cfg_config_dev { + const struct cs_cfg_config_desc *desc; + struct coresight_device *csdev; + struct list_head node; + unsigned long id_hash; + int nr_feat; + struct cs_cfg_feature **feats; + bool enabled; +}; + +/** + * Coresight device load ops. + * Registered coresight devices provide these operations to create 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 cs_cfg_feature). + */ +struct cs_cfg_dev_feat_ops { + int (*load_feat)(struct coresight_device *csdev, + const struct cs_cfg_feature_desc *feat_desc); +}; + #endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index d49bcace76c8..479dc81993c2 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -31,6 +31,130 @@ static struct device_type cscfg_dev_type = {
/* load features and configuations into the lists */
+/* get name feature instance from a coresight device list of features */ +static struct cs_cfg_feature * +cscfg_get_feat_csdev(struct coresight_device *csdev, const char *name) +{ + struct cs_cfg_feature *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 cs_cfg_config_dev * +cscfg_alloc_dev_cfg(struct coresight_device *csdev, int nr_feats) +{ + struct cs_cfg_config_dev *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 cs_cfg_config_dev), GFP_KERNEL); + if (dev_cfg) { + dev_cfg->csdev = csdev; + dev_cfg->feats = devm_kcalloc(dev, nr_feats, + sizeof(struct cs_cfg_feature *), + 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 cs_cfg_match_info *used_cmp, + struct cs_cfg_match_info *reg_dev) +{ + /* if flags don't match then fail early */ + if (!(used_cmp->flags & reg_dev->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_dev_cfg(struct coresight_device *csdev, + struct cs_cfg_match_info *match_info, + struct cs_cfg_config *cfg) +{ + struct cs_cfg_config_dev *dev_cfg = NULL; + struct cs_cfg_uses_feat_desc *used_feat; + struct cs_cfg_feature *feat; + int checked, nr_uses = cfg->desc->nr_uses; + + /* look at each required feature and see if it matches any feature on the device */ + for (checked = 0; checked < nr_uses; checked++) { + used_feat = &cfg->desc->uses[checked]; + if (cscfg_match_feat_info(&used_feat->match, match_info)) { + /* device matched - get the feature */ + feat = cscfg_get_feat_csdev(csdev, used_feat->name); + if (!feat) + return -EINVAL; + if (!dev_cfg) { + dev_cfg = cscfg_alloc_dev_cfg(csdev, nr_uses); + 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_devs(struct cs_cfg_config *cfg) +{ + struct cscfg_reg_csdev *curr_item; + int err; + + list_for_each_entry(curr_item, &cscfg_dev->dev_list, item) { + err = cscfg_add_dev_cfg(curr_item->csdev, &curr_item->match_info, cfg); + if (err) + return err; + } + 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_devs(struct cs_cfg_feature_desc *feat_desc) +{ + struct cscfg_reg_csdev *curr_item; + int err; + + list_for_each_entry(curr_item, &cscfg_dev->dev_list, item) { + if (curr_item->match_info.flags & feat_desc->match_flags) { + if (curr_item->ops.load_feat) { + err = curr_item->ops.load_feat(curr_item->csdev, feat_desc); + if (err) + return err; + } else + return -EINVAL; + } + } + return 0; +} + /* check feature list for a named feature - call with mutex locked. */ static bool cscfg_match_list_feat(const char *name) { @@ -60,6 +184,7 @@ static int cscfg_check_feat_for_cfg(struct cs_cfg_config_desc *cfg_desc) static int cscfg_load_feat(struct cs_cfg_feature_desc *feat_desc) { struct cscfg_featlist_item *feat_item; + int err;
if (!cscfg_dev) return -ENODEV; @@ -71,6 +196,11 @@ static int cscfg_load_feat(struct cs_cfg_feature_desc *feat_desc) if (!feat_item) return -ENOMEM;
+ /* add feature to any matching registered devices */ + err = cscfg_add_feat_to_devs(feat_desc); + if (err) + return err; + feat_item->desc = feat_desc; list_add(&feat_item->item, &cscfg_dev->feat_list);
@@ -101,6 +231,11 @@ static int cscfg_load_config(struct cs_cfg_config_desc *cfg_desc) return -ENOMEM; cfg->desc = cfg_desc;
+ /* add config to any matching registered device */ + err = cscfg_add_cfg_to_devs(cfg); + if (err) + return err; + list_add(&cfg->item, &cscfg_dev->config_list);
return 0; @@ -145,6 +280,139 @@ int cscfg_load_config_sets(struct cs_cfg_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_cfg_csdev(struct coresight_device *csdev, + struct cs_cfg_match_info *info) +{ + struct cs_cfg_config *curr_item; + int err = 0; + + list_for_each_entry(curr_item, &cscfg_dev->config_list, item) { + err = cscfg_add_dev_cfg(csdev, info, curr_item); + if (err) + break; + } + return err; +} + +/* iterate through feature lists and load matching features to device */ +static int cscfg_add_feat_csdev(struct coresight_device *csdev, + struct cs_cfg_match_info *info, + struct cs_cfg_dev_feat_ops *ops) +{ + struct cscfg_featlist_item *curr_item; + int err = 0; + + if (!ops->load_feat) + return -EINVAL; + + list_for_each_entry(curr_item, &cscfg_dev->feat_list, item) { + if (curr_item->desc->match_flags & info->flags) { + /* pass the feature descriptor to the device load op */ + err = ops->load_feat(csdev, curr_item->desc); + if (err) + break; + } + } + return err; +} + +/* Add coresight device to list and copy its matching info */ +static int cscfg_list_add_entry(struct coresight_device *csdev, + struct cs_cfg_match_info *info, + struct cs_cfg_dev_feat_ops *ops) +{ + struct device *dev = to_device_cscfg(); + struct cscfg_reg_csdev *list_entry; + const char *name = NULL; + + list_entry = devm_kzalloc(dev, sizeof(struct cscfg_reg_csdev), GFP_KERNEL); + if (!list_entry) + return -ENOMEM; + if (info->dev_name) { + name = devm_kstrdup(dev, info->dev_name, GFP_KERNEL); + if (!name) + return -ENOMEM; + } + + list_entry->csdev = csdev; + list_entry->match_info.flags = info->flags; + list_entry->match_info.dev_name = name; + list_entry->ops.load_feat = ops->load_feat; + list_add(&list_entry->item, &cscfg_dev->dev_list); + + INIT_LIST_HEAD(&csdev->feat_list); + INIT_LIST_HEAD(&csdev->syscfg_list); + spin_lock_init(&csdev->cfg_lock); + + return 0; +} + +/* remove entry from registered device list */ +static bool cscfg_list_remove_entry(struct coresight_device *csdev) +{ + struct cscfg_reg_csdev *curr_item, *tmp; + + list_for_each_entry_safe(curr_item, tmp, &cscfg_dev->dev_list, item) { + if (curr_item->csdev == csdev) { + list_del(&curr_item->item); + return true; + } + } + return false; +} + +/* register a coresight device with the cs_syscfg device */ +int cscfg_register_csdev(struct coresight_device *csdev, + struct cs_cfg_match_info *info, + struct cs_cfg_dev_feat_ops *ops) +{ + int ret = 0; + + mutex_lock(&cs_cfg_mutex); + + if (!cscfg_dev) { + ret = -ENODEV; + goto reg_csdev_unlock; + } + + /* add device to list of registered devices */ + ret = cscfg_list_add_entry(csdev, info, ops); + if (ret) + goto reg_csdev_unlock; + + /* now load any registered features and configs matching the device. */ + ret = cscfg_add_feat_csdev(csdev, info, ops); + if (ret) + goto reg_csdev_unlock; + + ret = cscfg_add_cfg_csdev(csdev, info); + if (ret) + goto reg_csdev_unlock; + + cscfg_dev->nr_csdev++; + dev_info(&csdev->dev, "CSCFG registered %s", dev_name(&csdev->dev)); + +reg_csdev_unlock: + mutex_unlock(&cs_cfg_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) +{ + mutex_lock(&cs_cfg_mutex); + if (cscfg_dev) { + if (cscfg_list_remove_entry(csdev)) + cscfg_dev->nr_csdev--; + } + mutex_unlock(&cs_cfg_mutex); +} +EXPORT_SYMBOL_GPL(cscfg_unregister_csdev); + /* cs_syscfg device instance handling */ static void cscfg_device_release(struct device *dev) { diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index b3d41096382d..8ba800cc2e42 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -9,6 +9,8 @@ #include <linux/coresight.h> #include <linux/device.h>
+#include "coresight-config.h" + /** * System configuration device. * @@ -52,6 +54,22 @@ struct cs_cfg_config { struct list_head item; };
+/** + * 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_reg_csdev { + struct coresight_device *csdev; + struct cs_cfg_match_info match_info; + struct cs_cfg_dev_feat_ops ops; + struct list_head item; +}; + /* internal core operations for cscfg */ int cscfg_create_device(void); void cscfg_clear_device(void); @@ -61,5 +79,9 @@ void cscfg_driver_exit(void); /* syscfg external API */ int cscfg_load_config_sets(struct cs_cfg_config_desc **cfg_descs, struct cs_cfg_feature_desc **feat_descs); +int cscfg_register_csdev(struct coresight_device *csdev, + struct cs_cfg_match_info *info, + struct cs_cfg_dev_feat_ops *ops); +void cscfg_unregister_csdev(struct coresight_device *csdev);
#endif /* CORESIGHT_SYSCFG_H */ diff --git a/include/linux/coresight.h b/include/linux/coresight.h index ed0a9d938303..120eb6af4a80 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -190,6 +190,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; @@ -210,6 +213,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 Thu, Aug 27, 2020 at 03:34:06PM +0100, Mike Leach wrote:
API for individual devices to register with the cs_syscfg driver 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 | 119 ++++++++ .../hwtracing/coresight/coresight-syscfg.c | 268 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 22 ++ include/linux/coresight.h | 7 + 4 files changed, 416 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 413509f7d817..949a078c4692 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -151,4 +151,123 @@ struct cs_cfg_config_desc { const u64 *presets; /* nr_presets * nr_total_params */ }; +/**
- config register instance - part of a loaded feature.
maps register values to 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 cs_cfg_reg {
- union cs_cfg_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 cs_cfg_parameter {
- struct cs_cfg_feature *feat;
- struct cs_cfg_reg *reg;
- u64 current_value;
- bool val64;
+};
+/**
- cs_cfg_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 cs_cfg_feat_ops {
- int (*set_on_enable)(struct cs_cfg_feature *feat, const bool force_set);
- void (*save_on_disable)(struct cs_cfg_feature *feat, const bool force_save);
- void (*reset)(struct cs_cfg_feature *feat);
+};
+/**
- Feature instance loaded into a CoreSight device driver.
- 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 (@dev_spinlock).
- @desc: pointer to the static descriptor for this feature.
- @csdev: parent CoreSight device instance.
- @node: list entry into feature list for this device.
- @dev_spinlock: device spinlock..
- @enabled: feature is enabled on this device.
- @nr_params: number of parameters.
- @params: current parameter values on this device
- @param_group: sysfs group for feature parameters.
- @ops: standard ops to enable and disable features on devices.
- */
+struct cs_cfg_feature {
- const struct cs_cfg_feature_desc *desc;
- struct coresight_device *csdev;
- struct list_head node;
- spinlock_t *dev_spinlock;
- bool enabled;
- int nr_params;
- struct cs_cfg_parameter *params;
- struct attribute_group *param_group;
- int nr_regs;
- struct cs_cfg_reg *regs;
- struct cs_cfg_feat_ops ops;
+};
+/**
- Configuration instance when loaded into a 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 cs_cfg_config_dev {
Can we make cs_cfg_feature and cs_cfg_config_dev more similar? Something like cscfg_feature_csdev and cscfg_config_csdev. That way it is easy to remember and there is no misunderstanding as to what they do.
- const struct cs_cfg_config_desc *desc;
- struct coresight_device *csdev;
- struct list_head node;
- unsigned long id_hash;
- int nr_feat;
- struct cs_cfg_feature **feats;
- bool enabled;
+};
+/**
- Coresight device load ops.
- Registered coresight devices provide these operations to create 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 cs_cfg_feature).
- */
+struct cs_cfg_dev_feat_ops {
- int (*load_feat)(struct coresight_device *csdev,
const struct cs_cfg_feature_desc *feat_desc);
+};
#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index d49bcace76c8..479dc81993c2 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -31,6 +31,130 @@ static struct device_type cscfg_dev_type = { /* load features and configuations into the lists */ +/* get name feature instance from a coresight device list of features */ +static struct cs_cfg_feature * +cscfg_get_feat_csdev(struct coresight_device *csdev, const char *name) +{
- struct cs_cfg_feature *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 cs_cfg_config_dev * +cscfg_alloc_dev_cfg(struct coresight_device *csdev, int nr_feats) +{
- struct cs_cfg_config_dev *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 cs_cfg_config_dev), GFP_KERNEL);
if (!dev_cfg) return NULL;
- if (dev_cfg) {
dev_cfg->csdev = csdev;
dev_cfg->feats = devm_kcalloc(dev, nr_feats,
sizeof(struct cs_cfg_feature *),
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 cs_cfg_match_info *used_cmp,
struct cs_cfg_match_info *reg_dev)
+{
- /* if flags don't match then fail early */
- if (!(used_cmp->flags & reg_dev->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_dev_cfg(struct coresight_device *csdev,
struct cs_cfg_match_info *match_info,
struct cs_cfg_config *cfg)
+{
- struct cs_cfg_config_dev *dev_cfg = NULL;
- struct cs_cfg_uses_feat_desc *used_feat;
- struct cs_cfg_feature *feat;
- int checked, nr_uses = cfg->desc->nr_uses;
- /* look at each required feature and see if it matches any feature on the device */
- for (checked = 0; checked < nr_uses; checked++) {
used_feat = &cfg->desc->uses[checked];
if (cscfg_match_feat_info(&used_feat->match, match_info)) {
/* device matched - get the feature */
feat = cscfg_get_feat_csdev(csdev, used_feat->name);
if (!feat)
return -EINVAL;
if (!dev_cfg) {
dev_cfg = cscfg_alloc_dev_cfg(csdev, nr_uses);
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_devs(struct cs_cfg_config *cfg) +{
cscfg_add_cfg_to_csdevs()
- struct cscfg_reg_csdev *curr_item;
- int err;
- list_for_each_entry(curr_item, &cscfg_dev->dev_list, item) {
err = cscfg_add_dev_cfg(curr_item->csdev, &curr_item->match_info, cfg);
cscfg_add_csdev_cfg()
if (err)
return err;
- }
- 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_devs(struct cs_cfg_feature_desc *feat_desc) +{
cscfg_add_feat_do_csdev()
- struct cscfg_reg_csdev *curr_item;
- int err;
- list_for_each_entry(curr_item, &cscfg_dev->dev_list, item) {
if (curr_item->match_info.flags & feat_desc->match_flags) {
if (curr_item->ops.load_feat) {
err = curr_item->ops.load_feat(curr_item->csdev, feat_desc);
if (err)
return err;
} else
return -EINVAL;
}
- }
- return 0;
+}
/* check feature list for a named feature - call with mutex locked. */ static bool cscfg_match_list_feat(const char *name) { @@ -60,6 +184,7 @@ static int cscfg_check_feat_for_cfg(struct cs_cfg_config_desc *cfg_desc) static int cscfg_load_feat(struct cs_cfg_feature_desc *feat_desc) { struct cscfg_featlist_item *feat_item;
- int err;
if (!cscfg_dev) return -ENODEV; @@ -71,6 +196,11 @@ static int cscfg_load_feat(struct cs_cfg_feature_desc *feat_desc) if (!feat_item) return -ENOMEM;
- /* add feature to any matching registered devices */
- err = cscfg_add_feat_to_devs(feat_desc);
- if (err)
return err;
- feat_item->desc = feat_desc; list_add(&feat_item->item, &cscfg_dev->feat_list);
@@ -101,6 +231,11 @@ static int cscfg_load_config(struct cs_cfg_config_desc *cfg_desc) return -ENOMEM; cfg->desc = cfg_desc;
- /* add config to any matching registered device */
- err = cscfg_add_cfg_to_devs(cfg);
- if (err)
return err;
- list_add(&cfg->item, &cscfg_dev->config_list);
return 0; @@ -145,6 +280,139 @@ int cscfg_load_config_sets(struct cs_cfg_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_cfg_csdev(struct coresight_device *csdev,
struct cs_cfg_match_info *info)
+{
- struct cs_cfg_config *curr_item;
- int err = 0;
- list_for_each_entry(curr_item, &cscfg_dev->config_list, item) {
err = cscfg_add_dev_cfg(csdev, info, curr_item);
if (err)
break;
- }
- return err;
+}
+/* iterate through feature lists and load matching features to device */ +static int cscfg_add_feat_csdev(struct coresight_device *csdev,
struct cs_cfg_match_info *info,
struct cs_cfg_dev_feat_ops *ops)
+{
- struct cscfg_featlist_item *curr_item;
- int err = 0;
- if (!ops->load_feat)
return -EINVAL;
- list_for_each_entry(curr_item, &cscfg_dev->feat_list, item) {
if (curr_item->desc->match_flags & info->flags) {
/* pass the feature descriptor to the device load op */
err = ops->load_feat(csdev, curr_item->desc);
if (err)
break;
}
- }
- return err;
+}
+/* Add coresight device to list and copy its matching info */ +static int cscfg_list_add_entry(struct coresight_device *csdev,
struct cs_cfg_match_info *info,
struct cs_cfg_dev_feat_ops *ops)
+{
- struct device *dev = to_device_cscfg();
- struct cscfg_reg_csdev *list_entry;
- const char *name = NULL;
- list_entry = devm_kzalloc(dev, sizeof(struct cscfg_reg_csdev), GFP_KERNEL);
- if (!list_entry)
return -ENOMEM;
- if (info->dev_name) {
name = devm_kstrdup(dev, info->dev_name, GFP_KERNEL);
if (!name)
return -ENOMEM;
- }
- list_entry->csdev = csdev;
We need to make sure @csdev doesn't go away while we hold a reference to it. To do that I suggest to use coresight_get_ref() after making it a public function. You will also need to move pm_runtime_get_sync() out of there and back in coresight_grab_device(). Releasing the reference count to @csdev using coresight_put_ref() also has to be done in cscfg_list_remove_entry().
- list_entry->match_info.flags = info->flags;
- list_entry->match_info.dev_name = name;
- list_entry->ops.load_feat = ops->load_feat;
- list_add(&list_entry->item, &cscfg_dev->dev_list);
- INIT_LIST_HEAD(&csdev->feat_list);
- INIT_LIST_HEAD(&csdev->syscfg_list);
- spin_lock_init(&csdev->cfg_lock);
- return 0;
+}
+/* remove entry from registered device list */ +static bool cscfg_list_remove_entry(struct coresight_device *csdev) +{
- struct cscfg_reg_csdev *curr_item, *tmp;
- list_for_each_entry_safe(curr_item, tmp, &cscfg_dev->dev_list, item) {
if (curr_item->csdev == csdev) {
list_del(&curr_item->item);
return true;
}
- }
- return false;
+}
+/* register a coresight device with the cs_syscfg device */ +int cscfg_register_csdev(struct coresight_device *csdev,
struct cs_cfg_match_info *info,
struct cs_cfg_dev_feat_ops *ops)
+{
- int ret = 0;
- mutex_lock(&cs_cfg_mutex);
- if (!cscfg_dev) {
ret = -ENODEV;
goto reg_csdev_unlock;
- }
- /* add device to list of registered devices */
- ret = cscfg_list_add_entry(csdev, info, ops);
- if (ret)
goto reg_csdev_unlock;
- /* now load any registered features and configs matching the device. */
- ret = cscfg_add_feat_csdev(csdev, info, ops);
- if (ret)
goto reg_csdev_unlock;
- ret = cscfg_add_cfg_csdev(csdev, info);
- if (ret)
goto reg_csdev_unlock;
- cscfg_dev->nr_csdev++;
- dev_info(&csdev->dev, "CSCFG registered %s", dev_name(&csdev->dev));
+reg_csdev_unlock:
- mutex_unlock(&cs_cfg_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) +{
- mutex_lock(&cs_cfg_mutex);
- if (cscfg_dev) {
if (cscfg_list_remove_entry(csdev))
cscfg_dev->nr_csdev--;
- }
- mutex_unlock(&cs_cfg_mutex);
+} +EXPORT_SYMBOL_GPL(cscfg_unregister_csdev);
/* cs_syscfg device instance handling */ static void cscfg_device_release(struct device *dev) { diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index b3d41096382d..8ba800cc2e42 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -9,6 +9,8 @@ #include <linux/coresight.h> #include <linux/device.h> +#include "coresight-config.h"
/**
- System configuration device.
@@ -52,6 +54,22 @@ struct cs_cfg_config { struct list_head item; }; +/**
- 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_reg_csdev {
Please call this cscfg_registered_csdev. I agree it is long but there is no doubt about what its purpose is when reading the code.
- struct coresight_device *csdev;
- struct cs_cfg_match_info match_info;
- struct cs_cfg_dev_feat_ops ops;
Are you planning any more operations because right now there is only a single one, i.e load_feat().
- struct list_head item;
+};
/* internal core operations for cscfg */ int cscfg_create_device(void); void cscfg_clear_device(void); @@ -61,5 +79,9 @@ void cscfg_driver_exit(void); /* syscfg external API */ int cscfg_load_config_sets(struct cs_cfg_config_desc **cfg_descs, struct cs_cfg_feature_desc **feat_descs); +int cscfg_register_csdev(struct coresight_device *csdev,
struct cs_cfg_match_info *info,
struct cs_cfg_dev_feat_ops *ops);
+void cscfg_unregister_csdev(struct coresight_device *csdev); #endif /* CORESIGHT_SYSCFG_H */ diff --git a/include/linux/coresight.h b/include/linux/coresight.h index ed0a9d938303..120eb6af4a80 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -190,6 +190,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; @@ -210,6 +213,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;
}; /* -- 2.17.1
Hi Mathieu,
On Tue, 6 Oct 2020 at 23:37, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Thu, Aug 27, 2020 at 03:34:06PM +0100, Mike Leach wrote:
API for individual devices to register with the cs_syscfg driver 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 | 119 ++++++++ .../hwtracing/coresight/coresight-syscfg.c | 268 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 22 ++ include/linux/coresight.h | 7 + 4 files changed, 416 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 413509f7d817..949a078c4692 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -151,4 +151,123 @@ struct cs_cfg_config_desc { const u64 *presets; /* nr_presets * nr_total_params */ };
+/**
- config register instance - part of a loaded feature.
maps register values to 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 cs_cfg_reg {
union cs_cfg_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 cs_cfg_parameter {
struct cs_cfg_feature *feat;
struct cs_cfg_reg *reg;
u64 current_value;
bool val64;
+};
+/**
- cs_cfg_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 cs_cfg_feat_ops {
int (*set_on_enable)(struct cs_cfg_feature *feat, const bool force_set);
void (*save_on_disable)(struct cs_cfg_feature *feat, const bool force_save);
void (*reset)(struct cs_cfg_feature *feat);
+};
+/**
- Feature instance loaded into a CoreSight device driver.
- 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 (@dev_spinlock).
- @desc: pointer to the static descriptor for this feature.
- @csdev: parent CoreSight device instance.
- @node: list entry into feature list for this device.
- @dev_spinlock: device spinlock..
- @enabled: feature is enabled on this device.
- @nr_params: number of parameters.
- @params: current parameter values on this device
- @param_group: sysfs group for feature parameters.
- @ops: standard ops to enable and disable features on devices.
- */
+struct cs_cfg_feature {
const struct cs_cfg_feature_desc *desc;
struct coresight_device *csdev;
struct list_head node;
spinlock_t *dev_spinlock;
bool enabled;
int nr_params;
struct cs_cfg_parameter *params;
struct attribute_group *param_group;
int nr_regs;
struct cs_cfg_reg *regs;
struct cs_cfg_feat_ops ops;
+};
+/**
- Configuration instance when loaded into a 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 cs_cfg_config_dev {
Can we make cs_cfg_feature and cs_cfg_config_dev more similar? Something like cscfg_feature_csdev and cscfg_config_csdev. That way it is easy to remember and there is no misunderstanding as to what they do.
I'd already dropped the dev from this one, but I like your idea of csdev better so I'll add it to both.
const struct cs_cfg_config_desc *desc;
struct coresight_device *csdev;
struct list_head node;
unsigned long id_hash;
int nr_feat;
struct cs_cfg_feature **feats;
bool enabled;
+};
+/**
- Coresight device load ops.
- Registered coresight devices provide these operations to create 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 cs_cfg_feature).
- */
+struct cs_cfg_dev_feat_ops {
int (*load_feat)(struct coresight_device *csdev,
const struct cs_cfg_feature_desc *feat_desc);
+};
#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index d49bcace76c8..479dc81993c2 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -31,6 +31,130 @@ static struct device_type cscfg_dev_type = {
/* load features and configuations into the lists */
+/* get name feature instance from a coresight device list of features */ +static struct cs_cfg_feature * +cscfg_get_feat_csdev(struct coresight_device *csdev, const char *name) +{
struct cs_cfg_feature *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 cs_cfg_config_dev * +cscfg_alloc_dev_cfg(struct coresight_device *csdev, int nr_feats) +{
struct cs_cfg_config_dev *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 cs_cfg_config_dev), GFP_KERNEL);
if (!dev_cfg) return NULL;
Will change.
if (dev_cfg) {
dev_cfg->csdev = csdev;
dev_cfg->feats = devm_kcalloc(dev, nr_feats,
sizeof(struct cs_cfg_feature *),
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 cs_cfg_match_info *used_cmp,
struct cs_cfg_match_info *reg_dev)
+{
/* if flags don't match then fail early */
if (!(used_cmp->flags & reg_dev->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_dev_cfg(struct coresight_device *csdev,
struct cs_cfg_match_info *match_info,
struct cs_cfg_config *cfg)
+{
struct cs_cfg_config_dev *dev_cfg = NULL;
struct cs_cfg_uses_feat_desc *used_feat;
struct cs_cfg_feature *feat;
int checked, nr_uses = cfg->desc->nr_uses;
/* look at each required feature and see if it matches any feature on the device */
for (checked = 0; checked < nr_uses; checked++) {
used_feat = &cfg->desc->uses[checked];
if (cscfg_match_feat_info(&used_feat->match, match_info)) {
/* device matched - get the feature */
feat = cscfg_get_feat_csdev(csdev, used_feat->name);
if (!feat)
return -EINVAL;
if (!dev_cfg) {
dev_cfg = cscfg_alloc_dev_cfg(csdev, nr_uses);
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_devs(struct cs_cfg_config *cfg) +{
cscfg_add_cfg_to_csdevs()
agreed - and for all dev => csdev
struct cscfg_reg_csdev *curr_item;
int err;
list_for_each_entry(curr_item, &cscfg_dev->dev_list, item) {
err = cscfg_add_dev_cfg(curr_item->csdev, &curr_item->match_info, cfg);
cscfg_add_csdev_cfg()
if (err)
return err;
}
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_devs(struct cs_cfg_feature_desc *feat_desc) +{
cscfg_add_feat_do_csdev()
struct cscfg_reg_csdev *curr_item;
int err;
list_for_each_entry(curr_item, &cscfg_dev->dev_list, item) {
if (curr_item->match_info.flags & feat_desc->match_flags) {
if (curr_item->ops.load_feat) {
err = curr_item->ops.load_feat(curr_item->csdev, feat_desc);
if (err)
return err;
} else
return -EINVAL;
}
}
return 0;
+}
/* check feature list for a named feature - call with mutex locked. */ static bool cscfg_match_list_feat(const char *name) { @@ -60,6 +184,7 @@ static int cscfg_check_feat_for_cfg(struct cs_cfg_config_desc *cfg_desc) static int cscfg_load_feat(struct cs_cfg_feature_desc *feat_desc) { struct cscfg_featlist_item *feat_item;
int err; if (!cscfg_dev) return -ENODEV;
@@ -71,6 +196,11 @@ static int cscfg_load_feat(struct cs_cfg_feature_desc *feat_desc) if (!feat_item) return -ENOMEM;
/* add feature to any matching registered devices */
err = cscfg_add_feat_to_devs(feat_desc);
if (err)
return err;
feat_item->desc = feat_desc; list_add(&feat_item->item, &cscfg_dev->feat_list);
@@ -101,6 +231,11 @@ static int cscfg_load_config(struct cs_cfg_config_desc *cfg_desc) return -ENOMEM; cfg->desc = cfg_desc;
/* add config to any matching registered device */
err = cscfg_add_cfg_to_devs(cfg);
if (err)
return err;
list_add(&cfg->item, &cscfg_dev->config_list); return 0;
@@ -145,6 +280,139 @@ int cscfg_load_config_sets(struct cs_cfg_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_cfg_csdev(struct coresight_device *csdev,
struct cs_cfg_match_info *info)
+{
struct cs_cfg_config *curr_item;
int err = 0;
list_for_each_entry(curr_item, &cscfg_dev->config_list, item) {
err = cscfg_add_dev_cfg(csdev, info, curr_item);
if (err)
break;
}
return err;
+}
+/* iterate through feature lists and load matching features to device */ +static int cscfg_add_feat_csdev(struct coresight_device *csdev,
struct cs_cfg_match_info *info,
struct cs_cfg_dev_feat_ops *ops)
+{
struct cscfg_featlist_item *curr_item;
int err = 0;
if (!ops->load_feat)
return -EINVAL;
list_for_each_entry(curr_item, &cscfg_dev->feat_list, item) {
if (curr_item->desc->match_flags & info->flags) {
/* pass the feature descriptor to the device load op */
err = ops->load_feat(csdev, curr_item->desc);
if (err)
break;
}
}
return err;
+}
+/* Add coresight device to list and copy its matching info */ +static int cscfg_list_add_entry(struct coresight_device *csdev,
struct cs_cfg_match_info *info,
struct cs_cfg_dev_feat_ops *ops)
+{
struct device *dev = to_device_cscfg();
struct cscfg_reg_csdev *list_entry;
const char *name = NULL;
list_entry = devm_kzalloc(dev, sizeof(struct cscfg_reg_csdev), GFP_KERNEL);
if (!list_entry)
return -ENOMEM;
if (info->dev_name) {
name = devm_kstrdup(dev, info->dev_name, GFP_KERNEL);
if (!name)
return -ENOMEM;
}
list_entry->csdev = csdev;
We need to make sure @csdev doesn't go away while we hold a reference to it. To do that I suggest to use coresight_get_ref() after making it a public function. You will also need to move pm_runtime_get_sync() out of there and back in coresight_grab_device(). Releasing the reference count to @csdev using coresight_put_ref() also has to be done in cscfg_list_remove_entry().
This is guaranteed as csdevs are added to the list on cscfg_register_csdev(), - protected by the cscfg mutex, and removed on cscfg_unregister_csdev() - again protected by the mutex. These are called at the during the coresight_register / coresight_unregister phases for the driver - so the reference cannot disappear without it being unregistered, and the mutex prevents simultaneous register and unregister for a single device.
list_entry->match_info.flags = info->flags;
list_entry->match_info.dev_name = name;
list_entry->ops.load_feat = ops->load_feat;
list_add(&list_entry->item, &cscfg_dev->dev_list);
INIT_LIST_HEAD(&csdev->feat_list);
INIT_LIST_HEAD(&csdev->syscfg_list);
spin_lock_init(&csdev->cfg_lock);
return 0;
+}
+/* remove entry from registered device list */ +static bool cscfg_list_remove_entry(struct coresight_device *csdev) +{
struct cscfg_reg_csdev *curr_item, *tmp;
list_for_each_entry_safe(curr_item, tmp, &cscfg_dev->dev_list, item) {
if (curr_item->csdev == csdev) {
list_del(&curr_item->item);
return true;
}
}
return false;
+}
+/* register a coresight device with the cs_syscfg device */ +int cscfg_register_csdev(struct coresight_device *csdev,
struct cs_cfg_match_info *info,
struct cs_cfg_dev_feat_ops *ops)
+{
int ret = 0;
mutex_lock(&cs_cfg_mutex);
if (!cscfg_dev) {
ret = -ENODEV;
goto reg_csdev_unlock;
}
/* add device to list of registered devices */
ret = cscfg_list_add_entry(csdev, info, ops);
if (ret)
goto reg_csdev_unlock;
/* now load any registered features and configs matching the device. */
ret = cscfg_add_feat_csdev(csdev, info, ops);
if (ret)
goto reg_csdev_unlock;
ret = cscfg_add_cfg_csdev(csdev, info);
if (ret)
goto reg_csdev_unlock;
cscfg_dev->nr_csdev++;
dev_info(&csdev->dev, "CSCFG registered %s", dev_name(&csdev->dev));
+reg_csdev_unlock:
mutex_unlock(&cs_cfg_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) +{
mutex_lock(&cs_cfg_mutex);
if (cscfg_dev) {
if (cscfg_list_remove_entry(csdev))
cscfg_dev->nr_csdev--;
}
mutex_unlock(&cs_cfg_mutex);
+} +EXPORT_SYMBOL_GPL(cscfg_unregister_csdev);
/* cs_syscfg device instance handling */ static void cscfg_device_release(struct device *dev) { diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index b3d41096382d..8ba800cc2e42 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -9,6 +9,8 @@ #include <linux/coresight.h> #include <linux/device.h>
+#include "coresight-config.h"
/**
- System configuration device.
@@ -52,6 +54,22 @@ struct cs_cfg_config { struct list_head item; };
+/**
- 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_reg_csdev {
Please call this cscfg_registered_csdev. I agree it is long but there is no doubt about what its purpose is when reading the code.
struct coresight_device *csdev;
struct cs_cfg_match_info match_info;
struct cs_cfg_dev_feat_ops ops;
Are you planning any more operations because right now there is only a single one, i.e load_feat().
reset and enable - will be used if controlling trace / features from sysfs / configfs.
struct list_head item;
+};
/* internal core operations for cscfg */ int cscfg_create_device(void); void cscfg_clear_device(void); @@ -61,5 +79,9 @@ void cscfg_driver_exit(void); /* syscfg external API */ int cscfg_load_config_sets(struct cs_cfg_config_desc **cfg_descs, struct cs_cfg_feature_desc **feat_descs); +int cscfg_register_csdev(struct coresight_device *csdev,
struct cs_cfg_match_info *info,
struct cs_cfg_dev_feat_ops *ops);
+void cscfg_unregister_csdev(struct coresight_device *csdev);
#endif /* CORESIGHT_SYSCFG_H */ diff --git a/include/linux/coresight.h b/include/linux/coresight.h index ed0a9d938303..120eb6af4a80 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -190,6 +190,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; @@ -210,6 +213,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;
};
/*
2.17.1
Thanks for looking at this.
Mike
On Wed, Oct 07, 2020 at 12:15:52PM +0100, Mike Leach wrote:
Hi Mathieu,
On Tue, 6 Oct 2020 at 23:37, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Thu, Aug 27, 2020 at 03:34:06PM +0100, Mike Leach wrote:
API for individual devices to register with the cs_syscfg driver 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 | 119 ++++++++ .../hwtracing/coresight/coresight-syscfg.c | 268 ++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 22 ++ include/linux/coresight.h | 7 + 4 files changed, 416 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 413509f7d817..949a078c4692 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -151,4 +151,123 @@ struct cs_cfg_config_desc { const u64 *presets; /* nr_presets * nr_total_params */ };
+/**
- config register instance - part of a loaded feature.
maps register values to 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 cs_cfg_reg {
union cs_cfg_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 cs_cfg_parameter {
struct cs_cfg_feature *feat;
struct cs_cfg_reg *reg;
u64 current_value;
bool val64;
+};
+/**
- cs_cfg_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 cs_cfg_feat_ops {
int (*set_on_enable)(struct cs_cfg_feature *feat, const bool force_set);
void (*save_on_disable)(struct cs_cfg_feature *feat, const bool force_save);
void (*reset)(struct cs_cfg_feature *feat);
+};
+/**
- Feature instance loaded into a CoreSight device driver.
- 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 (@dev_spinlock).
- @desc: pointer to the static descriptor for this feature.
- @csdev: parent CoreSight device instance.
- @node: list entry into feature list for this device.
- @dev_spinlock: device spinlock..
- @enabled: feature is enabled on this device.
- @nr_params: number of parameters.
- @params: current parameter values on this device
- @param_group: sysfs group for feature parameters.
- @ops: standard ops to enable and disable features on devices.
- */
+struct cs_cfg_feature {
const struct cs_cfg_feature_desc *desc;
struct coresight_device *csdev;
struct list_head node;
spinlock_t *dev_spinlock;
bool enabled;
int nr_params;
struct cs_cfg_parameter *params;
struct attribute_group *param_group;
int nr_regs;
struct cs_cfg_reg *regs;
struct cs_cfg_feat_ops ops;
+};
+/**
- Configuration instance when loaded into a 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 cs_cfg_config_dev {
Can we make cs_cfg_feature and cs_cfg_config_dev more similar? Something like cscfg_feature_csdev and cscfg_config_csdev. That way it is easy to remember and there is no misunderstanding as to what they do.
I'd already dropped the dev from this one, but I like your idea of csdev better so I'll add it to both.
const struct cs_cfg_config_desc *desc;
struct coresight_device *csdev;
struct list_head node;
unsigned long id_hash;
int nr_feat;
struct cs_cfg_feature **feats;
bool enabled;
+};
+/**
- Coresight device load ops.
- Registered coresight devices provide these operations to create 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 cs_cfg_feature).
- */
+struct cs_cfg_dev_feat_ops {
int (*load_feat)(struct coresight_device *csdev,
const struct cs_cfg_feature_desc *feat_desc);
+};
#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index d49bcace76c8..479dc81993c2 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -31,6 +31,130 @@ static struct device_type cscfg_dev_type = {
/* load features and configuations into the lists */
+/* get name feature instance from a coresight device list of features */ +static struct cs_cfg_feature * +cscfg_get_feat_csdev(struct coresight_device *csdev, const char *name) +{
struct cs_cfg_feature *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 cs_cfg_config_dev * +cscfg_alloc_dev_cfg(struct coresight_device *csdev, int nr_feats) +{
struct cs_cfg_config_dev *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 cs_cfg_config_dev), GFP_KERNEL);
if (!dev_cfg) return NULL;
Will change.
if (dev_cfg) {
dev_cfg->csdev = csdev;
dev_cfg->feats = devm_kcalloc(dev, nr_feats,
sizeof(struct cs_cfg_feature *),
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 cs_cfg_match_info *used_cmp,
struct cs_cfg_match_info *reg_dev)
+{
/* if flags don't match then fail early */
if (!(used_cmp->flags & reg_dev->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_dev_cfg(struct coresight_device *csdev,
struct cs_cfg_match_info *match_info,
struct cs_cfg_config *cfg)
+{
struct cs_cfg_config_dev *dev_cfg = NULL;
struct cs_cfg_uses_feat_desc *used_feat;
struct cs_cfg_feature *feat;
int checked, nr_uses = cfg->desc->nr_uses;
/* look at each required feature and see if it matches any feature on the device */
for (checked = 0; checked < nr_uses; checked++) {
used_feat = &cfg->desc->uses[checked];
if (cscfg_match_feat_info(&used_feat->match, match_info)) {
/* device matched - get the feature */
feat = cscfg_get_feat_csdev(csdev, used_feat->name);
if (!feat)
return -EINVAL;
if (!dev_cfg) {
dev_cfg = cscfg_alloc_dev_cfg(csdev, nr_uses);
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_devs(struct cs_cfg_config *cfg) +{
cscfg_add_cfg_to_csdevs()
agreed - and for all dev => csdev
struct cscfg_reg_csdev *curr_item;
int err;
list_for_each_entry(curr_item, &cscfg_dev->dev_list, item) {
err = cscfg_add_dev_cfg(curr_item->csdev, &curr_item->match_info, cfg);
cscfg_add_csdev_cfg()
if (err)
return err;
}
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_devs(struct cs_cfg_feature_desc *feat_desc) +{
cscfg_add_feat_do_csdev()
struct cscfg_reg_csdev *curr_item;
int err;
list_for_each_entry(curr_item, &cscfg_dev->dev_list, item) {
if (curr_item->match_info.flags & feat_desc->match_flags) {
if (curr_item->ops.load_feat) {
err = curr_item->ops.load_feat(curr_item->csdev, feat_desc);
if (err)
return err;
} else
return -EINVAL;
}
}
return 0;
+}
/* check feature list for a named feature - call with mutex locked. */ static bool cscfg_match_list_feat(const char *name) { @@ -60,6 +184,7 @@ static int cscfg_check_feat_for_cfg(struct cs_cfg_config_desc *cfg_desc) static int cscfg_load_feat(struct cs_cfg_feature_desc *feat_desc) { struct cscfg_featlist_item *feat_item;
int err; if (!cscfg_dev) return -ENODEV;
@@ -71,6 +196,11 @@ static int cscfg_load_feat(struct cs_cfg_feature_desc *feat_desc) if (!feat_item) return -ENOMEM;
/* add feature to any matching registered devices */
err = cscfg_add_feat_to_devs(feat_desc);
if (err)
return err;
feat_item->desc = feat_desc; list_add(&feat_item->item, &cscfg_dev->feat_list);
@@ -101,6 +231,11 @@ static int cscfg_load_config(struct cs_cfg_config_desc *cfg_desc) return -ENOMEM; cfg->desc = cfg_desc;
/* add config to any matching registered device */
err = cscfg_add_cfg_to_devs(cfg);
if (err)
return err;
list_add(&cfg->item, &cscfg_dev->config_list); return 0;
@@ -145,6 +280,139 @@ int cscfg_load_config_sets(struct cs_cfg_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_cfg_csdev(struct coresight_device *csdev,
struct cs_cfg_match_info *info)
+{
struct cs_cfg_config *curr_item;
int err = 0;
list_for_each_entry(curr_item, &cscfg_dev->config_list, item) {
err = cscfg_add_dev_cfg(csdev, info, curr_item);
if (err)
break;
}
return err;
+}
+/* iterate through feature lists and load matching features to device */ +static int cscfg_add_feat_csdev(struct coresight_device *csdev,
struct cs_cfg_match_info *info,
struct cs_cfg_dev_feat_ops *ops)
+{
struct cscfg_featlist_item *curr_item;
int err = 0;
if (!ops->load_feat)
return -EINVAL;
list_for_each_entry(curr_item, &cscfg_dev->feat_list, item) {
if (curr_item->desc->match_flags & info->flags) {
/* pass the feature descriptor to the device load op */
err = ops->load_feat(csdev, curr_item->desc);
if (err)
break;
}
}
return err;
+}
+/* Add coresight device to list and copy its matching info */ +static int cscfg_list_add_entry(struct coresight_device *csdev,
struct cs_cfg_match_info *info,
struct cs_cfg_dev_feat_ops *ops)
+{
struct device *dev = to_device_cscfg();
struct cscfg_reg_csdev *list_entry;
const char *name = NULL;
list_entry = devm_kzalloc(dev, sizeof(struct cscfg_reg_csdev), GFP_KERNEL);
if (!list_entry)
return -ENOMEM;
if (info->dev_name) {
name = devm_kstrdup(dev, info->dev_name, GFP_KERNEL);
if (!name)
return -ENOMEM;
}
list_entry->csdev = csdev;
We need to make sure @csdev doesn't go away while we hold a reference to it. To do that I suggest to use coresight_get_ref() after making it a public function. You will also need to move pm_runtime_get_sync() out of there and back in coresight_grab_device(). Releasing the reference count to @csdev using coresight_put_ref() also has to be done in cscfg_list_remove_entry().
This is guaranteed as csdevs are added to the list on cscfg_register_csdev(), - protected by the cscfg mutex, and removed on cscfg_unregister_csdev() - again protected by the mutex. These are called at the during the coresight_register / coresight_unregister phases for the driver - so the reference cannot disappear without it being unregistered, and the mutex prevents simultaneous register and unregister for a single device.
Yes, you are correct.
list_entry->match_info.flags = info->flags;
list_entry->match_info.dev_name = name;
list_entry->ops.load_feat = ops->load_feat;
list_add(&list_entry->item, &cscfg_dev->dev_list);
INIT_LIST_HEAD(&csdev->feat_list);
INIT_LIST_HEAD(&csdev->syscfg_list);
spin_lock_init(&csdev->cfg_lock);
return 0;
+}
+/* remove entry from registered device list */ +static bool cscfg_list_remove_entry(struct coresight_device *csdev) +{
struct cscfg_reg_csdev *curr_item, *tmp;
list_for_each_entry_safe(curr_item, tmp, &cscfg_dev->dev_list, item) {
if (curr_item->csdev == csdev) {
list_del(&curr_item->item);
return true;
}
}
return false;
+}
+/* register a coresight device with the cs_syscfg device */ +int cscfg_register_csdev(struct coresight_device *csdev,
struct cs_cfg_match_info *info,
struct cs_cfg_dev_feat_ops *ops)
+{
int ret = 0;
mutex_lock(&cs_cfg_mutex);
if (!cscfg_dev) {
ret = -ENODEV;
goto reg_csdev_unlock;
}
/* add device to list of registered devices */
ret = cscfg_list_add_entry(csdev, info, ops);
if (ret)
goto reg_csdev_unlock;
/* now load any registered features and configs matching the device. */
ret = cscfg_add_feat_csdev(csdev, info, ops);
if (ret)
goto reg_csdev_unlock;
ret = cscfg_add_cfg_csdev(csdev, info);
if (ret)
goto reg_csdev_unlock;
cscfg_dev->nr_csdev++;
dev_info(&csdev->dev, "CSCFG registered %s", dev_name(&csdev->dev));
+reg_csdev_unlock:
mutex_unlock(&cs_cfg_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) +{
mutex_lock(&cs_cfg_mutex);
if (cscfg_dev) {
if (cscfg_list_remove_entry(csdev))
cscfg_dev->nr_csdev--;
}
mutex_unlock(&cs_cfg_mutex);
+} +EXPORT_SYMBOL_GPL(cscfg_unregister_csdev);
/* cs_syscfg device instance handling */ static void cscfg_device_release(struct device *dev) { diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index b3d41096382d..8ba800cc2e42 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -9,6 +9,8 @@ #include <linux/coresight.h> #include <linux/device.h>
+#include "coresight-config.h"
/**
- System configuration device.
@@ -52,6 +54,22 @@ struct cs_cfg_config { struct list_head item; };
+/**
- 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_reg_csdev {
Please call this cscfg_registered_csdev. I agree it is long but there is no doubt about what its purpose is when reading the code.
struct coresight_device *csdev;
struct cs_cfg_match_info match_info;
struct cs_cfg_dev_feat_ops ops;
Are you planning any more operations because right now there is only a single one, i.e load_feat().
reset and enable - will be used if controlling trace / features from sysfs / configfs.
struct list_head item;
+};
/* internal core operations for cscfg */ int cscfg_create_device(void); void cscfg_clear_device(void); @@ -61,5 +79,9 @@ void cscfg_driver_exit(void); /* syscfg external API */ int cscfg_load_config_sets(struct cs_cfg_config_desc **cfg_descs, struct cs_cfg_feature_desc **feat_descs); +int cscfg_register_csdev(struct coresight_device *csdev,
struct cs_cfg_match_info *info,
struct cs_cfg_dev_feat_ops *ops);
+void cscfg_unregister_csdev(struct coresight_device *csdev);
#endif /* CORESIGHT_SYSCFG_H */ diff --git a/include/linux/coresight.h b/include/linux/coresight.h index ed0a9d938303..120eb6af4a80 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -190,6 +190,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; @@ -210,6 +213,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;
};
/*
2.17.1
Thanks for looking at this.
Mike
-- 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 | 565 ++++++++++++++++++ .../hwtracing/coresight/coresight-config.h | 16 + 3 files changed, 582 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 3605dd770664..177bc6338312 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..96f8df59df58 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.c @@ -0,0 +1,565 @@ +// 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" + +static void coresight_cfg_init_reg_param(struct cs_cfg_parameter *param); + +/* + * Handlers for creating and manipulating the feature representation + * in sysfs. + */ + +/* base feature attribute info */ +struct feat_attr_info { + const char *name; + ssize_t (*show)(struct device *dev, struct device_attribute *attr, + char *buf); + ssize_t (*store)(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count); +}; + +static ssize_t cs_cfg_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dev_ext_attribute *eattr = + container_of(attr, struct dev_ext_attribute, attr); + struct cs_cfg_feature *feat = (struct cs_cfg_feature *)eattr->var; + int val; + + spin_lock(feat->dev_spinlock); + val = feat->enabled; + spin_unlock(feat->dev_spinlock); + + return scnprintf(buf, PAGE_SIZE, "%d\n", val); +} + +static ssize_t cs_cfg_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct dev_ext_attribute *eattr = + container_of(attr, struct dev_ext_attribute, attr); + struct cs_cfg_feature *feat = (struct cs_cfg_feature *)eattr->var; + + int val; + + spin_lock(feat->dev_spinlock); + if (!kstrtoint(buf, 0, &val)) + feat->enabled = val; + spin_unlock(feat->dev_spinlock); + + return size; +} + +static ssize_t cs_cfg_desc_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dev_ext_attribute *eattr = + container_of(attr, struct dev_ext_attribute, attr); + struct cs_cfg_feature *feat = (struct cs_cfg_feature *)eattr->var; + + return scnprintf(buf, PAGE_SIZE, "%s\n", feat->desc->brief); +} + +struct feat_attr_info feature_std_attr[] = { + { + .name = "enable", + .show = cs_cfg_enable_show, + .store = cs_cfg_enable_store, + }, + { + .name = "description", + .show = cs_cfg_desc_show, + }, + { 0 }, +}; + +static ssize_t cs_cfg_param_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dev_ext_attribute *eattr = + container_of(attr, struct dev_ext_attribute, attr); + struct cs_cfg_parameter *param = (struct cs_cfg_parameter *)eattr->var; + u64 val; + + spin_lock(param->feat->dev_spinlock); + val = param->current_value; + spin_unlock(param->feat->dev_spinlock); + + return scnprintf(buf, PAGE_SIZE, "%lld\n", val); +} + +static ssize_t cs_cfg_param_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct dev_ext_attribute *eattr = + container_of(attr, struct dev_ext_attribute, attr); + struct cs_cfg_parameter *param = (struct cs_cfg_parameter *)eattr->var; + u64 val; + + spin_lock(param->feat->dev_spinlock); + if (!kstrtoull(buf, 0, &val)) { + param->current_value = val; + coresight_cfg_init_reg_param(param); + } + spin_unlock(param->feat->dev_spinlock); + + return size; +} + +static struct attribute * +cs_cfg_sysfs_create_feat_attr(struct device *dev, struct cs_cfg_feature *feat, + struct feat_attr_info *info) +{ + struct dev_ext_attribute *eattr; + + eattr = devm_kzalloc(dev, sizeof(struct dev_ext_attribute), + GFP_KERNEL); + if (!eattr) + return NULL; + eattr->attr.attr.name = devm_kstrdup(dev, info->name, GFP_KERNEL); + eattr->attr.attr.mode = info->store ? 0644 : 0444; + eattr->attr.show = info->show; + eattr->attr.store = info->store; + eattr->var = feat; + return &eattr->attr.attr; +} + +static struct attribute * +cs_cfg_sysfs_create_param_attr(struct device *dev, const char *name, + struct cs_cfg_parameter *param) +{ + struct dev_ext_attribute *eattr; + + eattr = devm_kzalloc(dev, sizeof(struct dev_ext_attribute), + GFP_KERNEL); + if (!eattr) + return NULL; + + eattr->attr.attr.name = devm_kstrdup(dev, name, GFP_KERNEL); + eattr->attr.attr.mode = 0644; + eattr->attr.show = cs_cfg_param_show; + eattr->attr.store = cs_cfg_param_store; + eattr->var = param; + return &eattr->attr.attr; +} + +int coresight_cfg_sysfs_add_grp(struct cs_cfg_feature *feat) +{ + int p, attr_idx = 0; + struct attribute **attrs; + const char *name; + struct feat_attr_info *info; + struct device *dev = feat->csdev->dev.parent; + + /* create sysfs group in csdev */ + feat->param_group = devm_kzalloc(dev, sizeof(struct attribute_group), + GFP_KERNEL); + if (!feat->param_group) + return -ENOMEM; + + feat->param_group->name = devm_kasprintf(dev, GFP_KERNEL, "%s.feat", + feat->desc->name); + if (!feat->param_group->name) + return -ENOMEM; + + /* attributes - nr_params + enable + desc */ + attrs = devm_kcalloc(dev, feat->nr_params + 2, + sizeof(struct attribute *), GFP_KERNEL); + if (!attrs) + return -ENOMEM; + + /* create base attributes in group */ + while (feature_std_attr[attr_idx].name) { + info = &feature_std_attr[attr_idx]; + attrs[attr_idx] = cs_cfg_sysfs_create_feat_attr(dev, feat, + info); + if (!attrs[attr_idx]) + return -ENOMEM; + attr_idx++; + } + + /* create params in group */ + for (p = 0; p < feat->nr_params; p++) { + name = feat->desc->params[p].name; + attrs[attr_idx] = + cs_cfg_sysfs_create_param_attr(dev, name, + &feat->params[p]); + if (!attrs[attr_idx]) + return -ENOMEM; + attr_idx++; + } + feat->param_group->attrs = attrs; + + return sysfs_create_group(&feat->csdev->dev.kobj, feat->param_group); +} +EXPORT_SYMBOL_GPL(coresight_cfg_sysfs_add_grp); + +/* + * standard routines to set/save/reset enabled features, and iterate + * groups of features on a device. + */ + +void coresight_cfg_list_add_feat(struct cs_cfg_feature *feat) +{ + spin_lock(&feat->csdev->cfg_lock); + list_add(&feat->node, &feat->csdev->feat_list); + spin_unlock(&feat->csdev->cfg_lock); +} +EXPORT_SYMBOL_GPL(coresight_cfg_list_add_feat); + +static void coresight_cfg_set_reg(struct cs_cfg_reg *reg, u32 flags) +{ + u32 *p_val32 = (u32 *)reg->drv_store; + u32 tmp32; + + if (!(flags & CS_CFG_REG_VAL_64BIT)) { + if (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; +} + +static void coresight_cfg_save_reg(struct cs_cfg_reg *reg, u32 flags) +{ + if (flags & CS_CFG_REG_VAL_64BIT) + reg->value.val64 = *(u64 *)(reg->drv_store); + else + reg->value.val32 = *(u32 *)(reg->drv_store); +} + +static void coresight_cfg_init_reg(struct cs_cfg_reg *reg, + const struct cs_cfg_reg_desc *desc) +{ + reg->value.val64 = desc->value.val64; +} + +static void coresight_cfg_init_reg_param(struct cs_cfg_parameter *param) +{ + 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 cs_cfg_set_on_enable(struct cs_cfg_feature *feat, const bool force_set) +{ + int i; + u32 flags; + + spin_lock(feat->dev_spinlock); + if (feat->enabled || force_set) { + for (i = 0; i < feat->nr_regs; i++) { + flags = feat->desc->regs[i].flags; + coresight_cfg_set_reg(&feat->regs[i], flags); + } + } + dev_dbg(&feat->csdev->dev, "Feature %s: %s", feat->desc->name, + feat->enabled || force_set ? "Set enabled" : "Skip disabled"); + spin_unlock(feat->dev_spinlock); + return 0; +} + +static void cs_cfg_save_on_disable(struct cs_cfg_feature *feat, const bool force_save) +{ + int i; + u32 flags; + + spin_lock(feat->dev_spinlock); + if (feat->enabled || force_save) { + for (i = 0; i < feat->nr_regs; i++) { + flags = feat->desc->regs[i].flags; + if (flags & CS_CFG_REG_VAL_SAVE) + coresight_cfg_save_reg(&feat->regs[i], flags); + } + } + dev_dbg(&feat->csdev->dev, "Feature %s: %s", feat->desc->name, + feat->enabled || force_save ? "Save disabled" : "Skip disabled"); + spin_unlock(feat->dev_spinlock); +} + +/* default reset - restore default values, disable feature */ +static void cs_cfg_reset_feat(struct cs_cfg_feature *feat) +{ + const struct cs_cfg_feature_desc *feat_desc = feat->desc; + struct cs_cfg_reg_desc *reg_desc; + struct cs_cfg_parameter *param; + struct cs_cfg_reg *reg; + int i; + u32 flags; + + spin_lock(feat->dev_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]; + flags = reg_desc->flags; + reg = &feat->regs[i]; + + /* check if reg set from a parameter otherwise desc default */ + if (flags & CS_CFG_REG_VAL_PARAM) { + param = &feat->params[reg_desc->value.val32]; + param->reg = reg; + param->val64 = flags & CS_CFG_REG_VAL_64BIT; + coresight_cfg_init_reg_param(param); + } else + coresight_cfg_init_reg(reg, reg_desc); + } + spin_unlock(feat->dev_spinlock); +} + +void coresight_cfg_set_def_ops(struct cs_cfg_feature *feat) +{ + feat->ops.set_on_enable = cs_cfg_set_on_enable; + feat->ops.save_on_disable = cs_cfg_save_on_disable; + feat->ops.reset = cs_cfg_reset_feat; +} +EXPORT_SYMBOL_GPL(coresight_cfg_set_def_ops); + +int coresight_cfg_set_enabled_feats(struct coresight_device *csdev) +{ + struct cs_cfg_feature *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(coresight_cfg_set_enabled_feats); + +void coresight_cfg_save_enabled_feats(struct coresight_device *csdev) +{ + struct cs_cfg_feature *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(coresight_cfg_save_enabled_feats); + +void coresight_cfg_reset_feats(struct coresight_device *csdev) +{ + struct cs_cfg_feature *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(coresight_cfg_reset_feats); + +static int coresight_cfg_update_presets(struct cs_cfg_config_dev *cfg, int preset) +{ + int i, j, line_offset = 0, val_idx = 0, max_idx; + u64 val; + struct cs_cfg_feature *feat; + struct cs_cfg_parameter *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->dev_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->dev_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 coresight_cfg_update_curr_params(struct cs_cfg_config_dev *cfg) +{ + int i, j; + struct cs_cfg_feature *feat; + struct cs_cfg_parameter *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->dev_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->dev_spinlock); + } + } + return 0; +} + +static int coresight_cfg_prog_config(struct cs_cfg_config_dev *cfg, bool enable) +{ + int i, err = 0; + struct cs_cfg_feature *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 coresight_cfg_enable_dev_config(struct coresight_device *csdev, + unsigned long cfg_id, + int preset) +{ + struct cs_cfg_config_dev *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 = coresight_cfg_update_presets(cfg, preset); + else + err = coresight_cfg_update_curr_params(cfg); + if (!err) + err = coresight_cfg_prog_config(cfg, true); + if (!err) + cfg->enabled = true; + break; + } + } + spin_unlock(&csdev->cfg_lock); + return err; +} +EXPORT_SYMBOL_GPL(coresight_cfg_enable_dev_config); + +void coresight_cfg_disable_dev_config(struct coresight_device *csdev) +{ + struct cs_cfg_config_dev *cfg; + + spin_lock(&csdev->cfg_lock); + list_for_each_entry(cfg, &csdev->syscfg_list, node) { + if (cfg->enabled) { + coresight_cfg_prog_config(cfg, false); + cfg->enabled = false; + } + } + spin_unlock(&csdev->cfg_lock); +} +EXPORT_SYMBOL_GPL(coresight_cfg_disable_dev_config); diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 949a078c4692..afecab88451a 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -270,4 +270,20 @@ struct cs_cfg_dev_feat_ops { const struct cs_cfg_feature_desc *feat_desc); };
+/* coresight config API functions */ + +/* helper functions for feature manipulation */ +int coresight_cfg_sysfs_add_grp(struct cs_cfg_feature *feat); +void coresight_cfg_set_def_ops(struct cs_cfg_feature *feat); +void coresight_cfg_list_add_feat(struct cs_cfg_feature *feat); + +/* enable / disable features or configs on a device */ +int coresight_cfg_set_enabled_feats(struct coresight_device *csdev); +void coresight_cfg_save_enabled_feats(struct coresight_device *csdev); +void coresight_cfg_reset_feats(struct coresight_device *csdev); +int coresight_cfg_enable_dev_config(struct coresight_device *csdev, + unsigned long cfg_id, + int preset); +void coresight_cfg_disable_dev_config(struct coresight_device *csdev); + #endif /* _CORESIGHT_CORESIGHT_CONFIG_H */
On Thu, Aug 27, 2020 at 03:34:07PM +0100, 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 | 565 ++++++++++++++++++ .../hwtracing/coresight/coresight-config.h | 16 + 3 files changed, 582 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 3605dd770664..177bc6338312 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..96f8df59df58 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.c @@ -0,0 +1,565 @@ +// 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"
+static void coresight_cfg_init_reg_param(struct cs_cfg_parameter *param);
+/*
- Handlers for creating and manipulating the feature representation
- in sysfs.
- */
+/* base feature attribute info */ +struct feat_attr_info {
- const char *name;
- ssize_t (*show)(struct device *dev, struct device_attribute *attr,
char *buf);
- ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
+};
+static ssize_t cs_cfg_enable_show(struct device *dev,
struct device_attribute *attr,
char *buf)
There is no need to have "char *buf" on a line by itself. Same for cs_cfg_param_show().
+{
- struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
- struct cs_cfg_feature *feat = (struct cs_cfg_feature *)eattr->var;
- int val;
- spin_lock(feat->dev_spinlock);
I would rename cs_cfg_featre::dev_spinlock to cs_cfg_feature::csdev_spinlock to remove any ambiguity.
- val = feat->enabled;
- spin_unlock(feat->dev_spinlock);
- return scnprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+static ssize_t cs_cfg_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
- struct cs_cfg_feature *feat = (struct cs_cfg_feature *)eattr->var;
- int val;
- spin_lock(feat->dev_spinlock);
- if (!kstrtoint(buf, 0, &val))
Please call kstrtoint() outside of the lock.
feat->enabled = val;
- spin_unlock(feat->dev_spinlock);
- return size;
+}
+static ssize_t cs_cfg_desc_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
- struct cs_cfg_feature *feat = (struct cs_cfg_feature *)eattr->var;
- return scnprintf(buf, PAGE_SIZE, "%s\n", feat->desc->brief);
+}
+struct feat_attr_info feature_std_attr[] = {
- {
.name = "enable",
.show = cs_cfg_enable_show,
.store = cs_cfg_enable_store,
- },
- {
.name = "description",
.show = cs_cfg_desc_show,
- },
- { 0 },
+};
+static ssize_t cs_cfg_param_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
- struct cs_cfg_parameter *param = (struct cs_cfg_parameter *)eattr->var;
- u64 val;
- spin_lock(param->feat->dev_spinlock);
- val = param->current_value;
- spin_unlock(param->feat->dev_spinlock);
- return scnprintf(buf, PAGE_SIZE, "%lld\n", val);
+}
+static ssize_t cs_cfg_param_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
- struct cs_cfg_parameter *param = (struct cs_cfg_parameter *)eattr->var;
- u64 val;
- spin_lock(param->feat->dev_spinlock);
- if (!kstrtoull(buf, 0, &val)) {
Same here.
param->current_value = val;
coresight_cfg_init_reg_param(param);
- }
- spin_unlock(param->feat->dev_spinlock);
- return size;
+}
+static struct attribute * +cs_cfg_sysfs_create_feat_attr(struct device *dev, struct cs_cfg_feature *feat,
struct feat_attr_info *info)
+{
- struct dev_ext_attribute *eattr;
- eattr = devm_kzalloc(dev, sizeof(struct dev_ext_attribute),
GFP_KERNEL);
- if (!eattr)
return NULL;
For concistency I would have expected a space here, as it is in cs_cfg_sysfs_create_param_attr().
- eattr->attr.attr.name = devm_kstrdup(dev, info->name, GFP_KERNEL);
- eattr->attr.attr.mode = info->store ? 0644 : 0444;
- eattr->attr.show = info->show;
- eattr->attr.store = info->store;
- eattr->var = feat;
- return &eattr->attr.attr;
+}
+static struct attribute * +cs_cfg_sysfs_create_param_attr(struct device *dev, const char *name,
struct cs_cfg_parameter *param)
+{
- struct dev_ext_attribute *eattr;
- eattr = devm_kzalloc(dev, sizeof(struct dev_ext_attribute),
GFP_KERNEL);
- if (!eattr)
return NULL;
- eattr->attr.attr.name = devm_kstrdup(dev, name, GFP_KERNEL);
- eattr->attr.attr.mode = 0644;
- eattr->attr.show = cs_cfg_param_show;
- eattr->attr.store = cs_cfg_param_store;
- eattr->var = param;
- return &eattr->attr.attr;
+}
+int coresight_cfg_sysfs_add_grp(struct cs_cfg_feature *feat) +{
- int p, attr_idx = 0;
- struct attribute **attrs;
- const char *name;
- struct feat_attr_info *info;
- struct device *dev = feat->csdev->dev.parent;
- /* create sysfs group in csdev */
- feat->param_group = devm_kzalloc(dev, sizeof(struct attribute_group),
GFP_KERNEL);
- if (!feat->param_group)
return -ENOMEM;
- feat->param_group->name = devm_kasprintf(dev, GFP_KERNEL, "%s.feat",
feat->desc->name);
- if (!feat->param_group->name)
return -ENOMEM;
- /* attributes - nr_params + enable + desc */
- attrs = devm_kcalloc(dev, feat->nr_params + 2,
sizeof(struct attribute *), GFP_KERNEL);
@attrs needs to be NULL terminated and I'm surprised it hasn't blown up in your face yet (or I've missed the NULL terminated slot).
- if (!attrs)
return -ENOMEM;
- /* create base attributes in group */
- while (feature_std_attr[attr_idx].name) {
info = &feature_std_attr[attr_idx];
attrs[attr_idx] = cs_cfg_sysfs_create_feat_attr(dev, feat,
info);
if (!attrs[attr_idx])
return -ENOMEM;
attr_idx++;
- }
- /* create params in group */
- for (p = 0; p < feat->nr_params; p++) {
name = feat->desc->params[p].name;
attrs[attr_idx] =
cs_cfg_sysfs_create_param_attr(dev, name,
&feat->params[p]);
attrs[attr_idx] = cs_cfg_sysfs_create_param_attr(dev, name, &feat->params[p]);
if (!attrs[attr_idx])
return -ENOMEM;
attr_idx++;
- }
- feat->param_group->attrs = attrs;
- return sysfs_create_group(&feat->csdev->dev.kobj, feat->param_group);
+} +EXPORT_SYMBOL_GPL(coresight_cfg_sysfs_add_grp);
+/*
- standard routines to set/save/reset enabled features, and iterate
- groups of features on a device.
- */
+void coresight_cfg_list_add_feat(struct cs_cfg_feature *feat) +{
- spin_lock(&feat->csdev->cfg_lock);
- list_add(&feat->node, &feat->csdev->feat_list);
- spin_unlock(&feat->csdev->cfg_lock);
+} +EXPORT_SYMBOL_GPL(coresight_cfg_list_add_feat);
+static void coresight_cfg_set_reg(struct cs_cfg_reg *reg, u32 flags) +{
- u32 *p_val32 = (u32 *)reg->drv_store;
- u32 tmp32;
- if (!(flags & CS_CFG_REG_VAL_64BIT)) {
if (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;
+}
+static void coresight_cfg_save_reg(struct cs_cfg_reg *reg, u32 flags) +{
- if (flags & CS_CFG_REG_VAL_64BIT)
reg->value.val64 = *(u64 *)(reg->drv_store);
- else
reg->value.val32 = *(u32 *)(reg->drv_store);
+}
+static void coresight_cfg_init_reg(struct cs_cfg_reg *reg,
const struct cs_cfg_reg_desc *desc)
Indentation problem.
It is hard to look a the rest of this patch without more context. As such I will come back to it as I look a the other patches in this series.
Thanks, Mathieu
+{
- reg->value.val64 = desc->value.val64;
+}
+static void coresight_cfg_init_reg_param(struct cs_cfg_parameter *param) +{
- 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 cs_cfg_set_on_enable(struct cs_cfg_feature *feat, const bool force_set) +{
- int i;
- u32 flags;
- spin_lock(feat->dev_spinlock);
- if (feat->enabled || force_set) {
for (i = 0; i < feat->nr_regs; i++) {
flags = feat->desc->regs[i].flags;
coresight_cfg_set_reg(&feat->regs[i], flags);
}
- }
- dev_dbg(&feat->csdev->dev, "Feature %s: %s", feat->desc->name,
feat->enabled || force_set ? "Set enabled" : "Skip disabled");
- spin_unlock(feat->dev_spinlock);
- return 0;
+}
+static void cs_cfg_save_on_disable(struct cs_cfg_feature *feat, const bool force_save) +{
- int i;
- u32 flags;
- spin_lock(feat->dev_spinlock);
- if (feat->enabled || force_save) {
for (i = 0; i < feat->nr_regs; i++) {
flags = feat->desc->regs[i].flags;
if (flags & CS_CFG_REG_VAL_SAVE)
coresight_cfg_save_reg(&feat->regs[i], flags);
}
- }
- dev_dbg(&feat->csdev->dev, "Feature %s: %s", feat->desc->name,
feat->enabled || force_save ? "Save disabled" : "Skip disabled");
- spin_unlock(feat->dev_spinlock);
+}
+/* default reset - restore default values, disable feature */ +static void cs_cfg_reset_feat(struct cs_cfg_feature *feat) +{
- const struct cs_cfg_feature_desc *feat_desc = feat->desc;
- struct cs_cfg_reg_desc *reg_desc;
- struct cs_cfg_parameter *param;
- struct cs_cfg_reg *reg;
- int i;
- u32 flags;
- spin_lock(feat->dev_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];
flags = reg_desc->flags;
reg = &feat->regs[i];
/* check if reg set from a parameter otherwise desc default */
if (flags & CS_CFG_REG_VAL_PARAM) {
param = &feat->params[reg_desc->value.val32];
param->reg = reg;
param->val64 = flags & CS_CFG_REG_VAL_64BIT;
coresight_cfg_init_reg_param(param);
} else
coresight_cfg_init_reg(reg, reg_desc);
- }
- spin_unlock(feat->dev_spinlock);
+}
+void coresight_cfg_set_def_ops(struct cs_cfg_feature *feat) +{
- feat->ops.set_on_enable = cs_cfg_set_on_enable;
- feat->ops.save_on_disable = cs_cfg_save_on_disable;
- feat->ops.reset = cs_cfg_reset_feat;
+} +EXPORT_SYMBOL_GPL(coresight_cfg_set_def_ops);
+int coresight_cfg_set_enabled_feats(struct coresight_device *csdev) +{
- struct cs_cfg_feature *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(coresight_cfg_set_enabled_feats);
+void coresight_cfg_save_enabled_feats(struct coresight_device *csdev) +{
- struct cs_cfg_feature *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(coresight_cfg_save_enabled_feats);
+void coresight_cfg_reset_feats(struct coresight_device *csdev) +{
- struct cs_cfg_feature *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(coresight_cfg_reset_feats);
+static int coresight_cfg_update_presets(struct cs_cfg_config_dev *cfg, int preset) +{
- int i, j, line_offset = 0, val_idx = 0, max_idx;
- u64 val;
- struct cs_cfg_feature *feat;
- struct cs_cfg_parameter *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->dev_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->dev_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 coresight_cfg_update_curr_params(struct cs_cfg_config_dev *cfg) +{
- int i, j;
- struct cs_cfg_feature *feat;
- struct cs_cfg_parameter *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->dev_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->dev_spinlock);
}
- }
- return 0;
+}
+static int coresight_cfg_prog_config(struct cs_cfg_config_dev *cfg, bool enable) +{
- int i, err = 0;
- struct cs_cfg_feature *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 coresight_cfg_enable_dev_config(struct coresight_device *csdev,
unsigned long cfg_id,
int preset)
+{
- struct cs_cfg_config_dev *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 = coresight_cfg_update_presets(cfg, preset);
else
err = coresight_cfg_update_curr_params(cfg);
if (!err)
err = coresight_cfg_prog_config(cfg, true);
if (!err)
cfg->enabled = true;
break;
}
- }
- spin_unlock(&csdev->cfg_lock);
- return err;
+} +EXPORT_SYMBOL_GPL(coresight_cfg_enable_dev_config);
+void coresight_cfg_disable_dev_config(struct coresight_device *csdev) +{
- struct cs_cfg_config_dev *cfg;
- spin_lock(&csdev->cfg_lock);
- list_for_each_entry(cfg, &csdev->syscfg_list, node) {
if (cfg->enabled) {
coresight_cfg_prog_config(cfg, false);
cfg->enabled = false;
}
- }
- spin_unlock(&csdev->cfg_lock);
+} +EXPORT_SYMBOL_GPL(coresight_cfg_disable_dev_config); diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 949a078c4692..afecab88451a 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -270,4 +270,20 @@ struct cs_cfg_dev_feat_ops { const struct cs_cfg_feature_desc *feat_desc); }; +/* coresight config API functions */
+/* helper functions for feature manipulation */ +int coresight_cfg_sysfs_add_grp(struct cs_cfg_feature *feat); +void coresight_cfg_set_def_ops(struct cs_cfg_feature *feat); +void coresight_cfg_list_add_feat(struct cs_cfg_feature *feat);
+/* enable / disable features or configs on a device */ +int coresight_cfg_set_enabled_feats(struct coresight_device *csdev); +void coresight_cfg_save_enabled_feats(struct coresight_device *csdev); +void coresight_cfg_reset_feats(struct coresight_device *csdev); +int coresight_cfg_enable_dev_config(struct coresight_device *csdev,
unsigned long cfg_id,
int preset);
+void coresight_cfg_disable_dev_config(struct coresight_device *csdev);
#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */
2.17.1
Hi Mathieu, Thanks for looking at this.
However, per your comment in the v1 set, for the next set I have moved management of features out of individual coresight device sysfs, and into a custom configfs directory. This actually makes things easter for the user - they can change a single parameter value and have it change on all device instances of the feature.
Regards
Mike
On Fri, 9 Oct 2020 at 22:34, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Thu, Aug 27, 2020 at 03:34:07PM +0100, 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 | 565 ++++++++++++++++++ .../hwtracing/coresight/coresight-config.h | 16 + 3 files changed, 582 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 3605dd770664..177bc6338312 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..96f8df59df58 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.c @@ -0,0 +1,565 @@ +// 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"
+static void coresight_cfg_init_reg_param(struct cs_cfg_parameter *param);
+/*
- Handlers for creating and manipulating the feature representation
- in sysfs.
- */
+/* base feature attribute info */ +struct feat_attr_info {
const char *name;
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
+};
+static ssize_t cs_cfg_enable_show(struct device *dev,
struct device_attribute *attr,
char *buf)
There is no need to have "char *buf" on a line by itself. Same for cs_cfg_param_show().
+{
struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
struct cs_cfg_feature *feat = (struct cs_cfg_feature *)eattr->var;
int val;
spin_lock(feat->dev_spinlock);
I would rename cs_cfg_featre::dev_spinlock to cs_cfg_feature::csdev_spinlock to remove any ambiguity.
val = feat->enabled;
spin_unlock(feat->dev_spinlock);
return scnprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+static ssize_t cs_cfg_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
struct cs_cfg_feature *feat = (struct cs_cfg_feature *)eattr->var;
int val;
spin_lock(feat->dev_spinlock);
if (!kstrtoint(buf, 0, &val))
Please call kstrtoint() outside of the lock.
feat->enabled = val;
spin_unlock(feat->dev_spinlock);
return size;
+}
+static ssize_t cs_cfg_desc_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
struct cs_cfg_feature *feat = (struct cs_cfg_feature *)eattr->var;
return scnprintf(buf, PAGE_SIZE, "%s\n", feat->desc->brief);
+}
+struct feat_attr_info feature_std_attr[] = {
{
.name = "enable",
.show = cs_cfg_enable_show,
.store = cs_cfg_enable_store,
},
{
.name = "description",
.show = cs_cfg_desc_show,
},
{ 0 },
+};
+static ssize_t cs_cfg_param_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
struct cs_cfg_parameter *param = (struct cs_cfg_parameter *)eattr->var;
u64 val;
spin_lock(param->feat->dev_spinlock);
val = param->current_value;
spin_unlock(param->feat->dev_spinlock);
return scnprintf(buf, PAGE_SIZE, "%lld\n", val);
+}
+static ssize_t cs_cfg_param_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
struct cs_cfg_parameter *param = (struct cs_cfg_parameter *)eattr->var;
u64 val;
spin_lock(param->feat->dev_spinlock);
if (!kstrtoull(buf, 0, &val)) {
Same here.
param->current_value = val;
coresight_cfg_init_reg_param(param);
}
spin_unlock(param->feat->dev_spinlock);
return size;
+}
+static struct attribute * +cs_cfg_sysfs_create_feat_attr(struct device *dev, struct cs_cfg_feature *feat,
struct feat_attr_info *info)
+{
struct dev_ext_attribute *eattr;
eattr = devm_kzalloc(dev, sizeof(struct dev_ext_attribute),
GFP_KERNEL);
if (!eattr)
return NULL;
For concistency I would have expected a space here, as it is in cs_cfg_sysfs_create_param_attr().
eattr->attr.attr.name = devm_kstrdup(dev, info->name, GFP_KERNEL);
eattr->attr.attr.mode = info->store ? 0644 : 0444;
eattr->attr.show = info->show;
eattr->attr.store = info->store;
eattr->var = feat;
return &eattr->attr.attr;
+}
+static struct attribute * +cs_cfg_sysfs_create_param_attr(struct device *dev, const char *name,
struct cs_cfg_parameter *param)
+{
struct dev_ext_attribute *eattr;
eattr = devm_kzalloc(dev, sizeof(struct dev_ext_attribute),
GFP_KERNEL);
if (!eattr)
return NULL;
eattr->attr.attr.name = devm_kstrdup(dev, name, GFP_KERNEL);
eattr->attr.attr.mode = 0644;
eattr->attr.show = cs_cfg_param_show;
eattr->attr.store = cs_cfg_param_store;
eattr->var = param;
return &eattr->attr.attr;
+}
+int coresight_cfg_sysfs_add_grp(struct cs_cfg_feature *feat) +{
int p, attr_idx = 0;
struct attribute **attrs;
const char *name;
struct feat_attr_info *info;
struct device *dev = feat->csdev->dev.parent;
/* create sysfs group in csdev */
feat->param_group = devm_kzalloc(dev, sizeof(struct attribute_group),
GFP_KERNEL);
if (!feat->param_group)
return -ENOMEM;
feat->param_group->name = devm_kasprintf(dev, GFP_KERNEL, "%s.feat",
feat->desc->name);
if (!feat->param_group->name)
return -ENOMEM;
/* attributes - nr_params + enable + desc */
attrs = devm_kcalloc(dev, feat->nr_params + 2,
sizeof(struct attribute *), GFP_KERNEL);
@attrs needs to be NULL terminated and I'm surprised it hasn't blown up in your face yet (or I've missed the NULL terminated slot).
if (!attrs)
return -ENOMEM;
/* create base attributes in group */
while (feature_std_attr[attr_idx].name) {
info = &feature_std_attr[attr_idx];
attrs[attr_idx] = cs_cfg_sysfs_create_feat_attr(dev, feat,
info);
if (!attrs[attr_idx])
return -ENOMEM;
attr_idx++;
}
/* create params in group */
for (p = 0; p < feat->nr_params; p++) {
name = feat->desc->params[p].name;
attrs[attr_idx] =
cs_cfg_sysfs_create_param_attr(dev, name,
&feat->params[p]);
attrs[attr_idx] = cs_cfg_sysfs_create_param_attr(dev, name, &feat->params[p]);
if (!attrs[attr_idx])
return -ENOMEM;
attr_idx++;
}
feat->param_group->attrs = attrs;
return sysfs_create_group(&feat->csdev->dev.kobj, feat->param_group);
+} +EXPORT_SYMBOL_GPL(coresight_cfg_sysfs_add_grp);
+/*
- standard routines to set/save/reset enabled features, and iterate
- groups of features on a device.
- */
+void coresight_cfg_list_add_feat(struct cs_cfg_feature *feat) +{
spin_lock(&feat->csdev->cfg_lock);
list_add(&feat->node, &feat->csdev->feat_list);
spin_unlock(&feat->csdev->cfg_lock);
+} +EXPORT_SYMBOL_GPL(coresight_cfg_list_add_feat);
+static void coresight_cfg_set_reg(struct cs_cfg_reg *reg, u32 flags) +{
u32 *p_val32 = (u32 *)reg->drv_store;
u32 tmp32;
if (!(flags & CS_CFG_REG_VAL_64BIT)) {
if (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;
+}
+static void coresight_cfg_save_reg(struct cs_cfg_reg *reg, u32 flags) +{
if (flags & CS_CFG_REG_VAL_64BIT)
reg->value.val64 = *(u64 *)(reg->drv_store);
else
reg->value.val32 = *(u32 *)(reg->drv_store);
+}
+static void coresight_cfg_init_reg(struct cs_cfg_reg *reg,
const struct cs_cfg_reg_desc *desc)
Indentation problem.
It is hard to look a the rest of this patch without more context. As such I will come back to it as I look a the other patches in this series.
Thanks, Mathieu
+{
reg->value.val64 = desc->value.val64;
+}
+static void coresight_cfg_init_reg_param(struct cs_cfg_parameter *param) +{
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 cs_cfg_set_on_enable(struct cs_cfg_feature *feat, const bool force_set) +{
int i;
u32 flags;
spin_lock(feat->dev_spinlock);
if (feat->enabled || force_set) {
for (i = 0; i < feat->nr_regs; i++) {
flags = feat->desc->regs[i].flags;
coresight_cfg_set_reg(&feat->regs[i], flags);
}
}
dev_dbg(&feat->csdev->dev, "Feature %s: %s", feat->desc->name,
feat->enabled || force_set ? "Set enabled" : "Skip disabled");
spin_unlock(feat->dev_spinlock);
return 0;
+}
+static void cs_cfg_save_on_disable(struct cs_cfg_feature *feat, const bool force_save) +{
int i;
u32 flags;
spin_lock(feat->dev_spinlock);
if (feat->enabled || force_save) {
for (i = 0; i < feat->nr_regs; i++) {
flags = feat->desc->regs[i].flags;
if (flags & CS_CFG_REG_VAL_SAVE)
coresight_cfg_save_reg(&feat->regs[i], flags);
}
}
dev_dbg(&feat->csdev->dev, "Feature %s: %s", feat->desc->name,
feat->enabled || force_save ? "Save disabled" : "Skip disabled");
spin_unlock(feat->dev_spinlock);
+}
+/* default reset - restore default values, disable feature */ +static void cs_cfg_reset_feat(struct cs_cfg_feature *feat) +{
const struct cs_cfg_feature_desc *feat_desc = feat->desc;
struct cs_cfg_reg_desc *reg_desc;
struct cs_cfg_parameter *param;
struct cs_cfg_reg *reg;
int i;
u32 flags;
spin_lock(feat->dev_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];
flags = reg_desc->flags;
reg = &feat->regs[i];
/* check if reg set from a parameter otherwise desc default */
if (flags & CS_CFG_REG_VAL_PARAM) {
param = &feat->params[reg_desc->value.val32];
param->reg = reg;
param->val64 = flags & CS_CFG_REG_VAL_64BIT;
coresight_cfg_init_reg_param(param);
} else
coresight_cfg_init_reg(reg, reg_desc);
}
spin_unlock(feat->dev_spinlock);
+}
+void coresight_cfg_set_def_ops(struct cs_cfg_feature *feat) +{
feat->ops.set_on_enable = cs_cfg_set_on_enable;
feat->ops.save_on_disable = cs_cfg_save_on_disable;
feat->ops.reset = cs_cfg_reset_feat;
+} +EXPORT_SYMBOL_GPL(coresight_cfg_set_def_ops);
+int coresight_cfg_set_enabled_feats(struct coresight_device *csdev) +{
struct cs_cfg_feature *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(coresight_cfg_set_enabled_feats);
+void coresight_cfg_save_enabled_feats(struct coresight_device *csdev) +{
struct cs_cfg_feature *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(coresight_cfg_save_enabled_feats);
+void coresight_cfg_reset_feats(struct coresight_device *csdev) +{
struct cs_cfg_feature *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(coresight_cfg_reset_feats);
+static int coresight_cfg_update_presets(struct cs_cfg_config_dev *cfg, int preset) +{
int i, j, line_offset = 0, val_idx = 0, max_idx;
u64 val;
struct cs_cfg_feature *feat;
struct cs_cfg_parameter *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->dev_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->dev_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 coresight_cfg_update_curr_params(struct cs_cfg_config_dev *cfg) +{
int i, j;
struct cs_cfg_feature *feat;
struct cs_cfg_parameter *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->dev_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->dev_spinlock);
}
}
return 0;
+}
+static int coresight_cfg_prog_config(struct cs_cfg_config_dev *cfg, bool enable) +{
int i, err = 0;
struct cs_cfg_feature *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 coresight_cfg_enable_dev_config(struct coresight_device *csdev,
unsigned long cfg_id,
int preset)
+{
struct cs_cfg_config_dev *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 = coresight_cfg_update_presets(cfg, preset);
else
err = coresight_cfg_update_curr_params(cfg);
if (!err)
err = coresight_cfg_prog_config(cfg, true);
if (!err)
cfg->enabled = true;
break;
}
}
spin_unlock(&csdev->cfg_lock);
return err;
+} +EXPORT_SYMBOL_GPL(coresight_cfg_enable_dev_config);
+void coresight_cfg_disable_dev_config(struct coresight_device *csdev) +{
struct cs_cfg_config_dev *cfg;
spin_lock(&csdev->cfg_lock);
list_for_each_entry(cfg, &csdev->syscfg_list, node) {
if (cfg->enabled) {
coresight_cfg_prog_config(cfg, false);
cfg->enabled = false;
}
}
spin_unlock(&csdev->cfg_lock);
+} +EXPORT_SYMBOL_GPL(coresight_cfg_disable_dev_config); diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 949a078c4692..afecab88451a 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -270,4 +270,20 @@ struct cs_cfg_dev_feat_ops { const struct cs_cfg_feature_desc *feat_desc); };
+/* coresight config API functions */
+/* helper functions for feature manipulation */ +int coresight_cfg_sysfs_add_grp(struct cs_cfg_feature *feat); +void coresight_cfg_set_def_ops(struct cs_cfg_feature *feat); +void coresight_cfg_list_add_feat(struct cs_cfg_feature *feat);
+/* enable / disable features or configs on a device */ +int coresight_cfg_set_enabled_feats(struct coresight_device *csdev); +void coresight_cfg_save_enabled_feats(struct coresight_device *csdev); +void coresight_cfg_reset_feats(struct coresight_device *csdev); +int coresight_cfg_enable_dev_config(struct coresight_device *csdev,
unsigned long cfg_id,
int preset);
+void coresight_cfg_disable_dev_config(struct coresight_device *csdev);
#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */
2.17.1
On Thu, Oct 29, 2020 at 06:31:53PM +0000, Mike Leach wrote:
Hi Mathieu, Thanks for looking at this.
However, per your comment in the v1 set, for the next set I have moved management of features out of individual coresight device sysfs, and into a custom configfs directory. This actually makes things easter for the user - they can change a single parameter value and have it change on all device instances of the feature.
Are you pointing out the comments I made in this patch no longer apply because you have changed your design? Have I understood you correctly?
Regards
Mike
On Fri, 9 Oct 2020 at 22:34, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Thu, Aug 27, 2020 at 03:34:07PM +0100, 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 | 565 ++++++++++++++++++ .../hwtracing/coresight/coresight-config.h | 16 + 3 files changed, 582 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 3605dd770664..177bc6338312 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..96f8df59df58 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.c @@ -0,0 +1,565 @@ +// 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"
+static void coresight_cfg_init_reg_param(struct cs_cfg_parameter *param);
+/*
- Handlers for creating and manipulating the feature representation
- in sysfs.
- */
+/* base feature attribute info */ +struct feat_attr_info {
const char *name;
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
+};
+static ssize_t cs_cfg_enable_show(struct device *dev,
struct device_attribute *attr,
char *buf)
There is no need to have "char *buf" on a line by itself. Same for cs_cfg_param_show().
+{
struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
struct cs_cfg_feature *feat = (struct cs_cfg_feature *)eattr->var;
int val;
spin_lock(feat->dev_spinlock);
I would rename cs_cfg_featre::dev_spinlock to cs_cfg_feature::csdev_spinlock to remove any ambiguity.
val = feat->enabled;
spin_unlock(feat->dev_spinlock);
return scnprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+static ssize_t cs_cfg_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
struct cs_cfg_feature *feat = (struct cs_cfg_feature *)eattr->var;
int val;
spin_lock(feat->dev_spinlock);
if (!kstrtoint(buf, 0, &val))
Please call kstrtoint() outside of the lock.
feat->enabled = val;
spin_unlock(feat->dev_spinlock);
return size;
+}
+static ssize_t cs_cfg_desc_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
struct cs_cfg_feature *feat = (struct cs_cfg_feature *)eattr->var;
return scnprintf(buf, PAGE_SIZE, "%s\n", feat->desc->brief);
+}
+struct feat_attr_info feature_std_attr[] = {
{
.name = "enable",
.show = cs_cfg_enable_show,
.store = cs_cfg_enable_store,
},
{
.name = "description",
.show = cs_cfg_desc_show,
},
{ 0 },
+};
+static ssize_t cs_cfg_param_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
struct cs_cfg_parameter *param = (struct cs_cfg_parameter *)eattr->var;
u64 val;
spin_lock(param->feat->dev_spinlock);
val = param->current_value;
spin_unlock(param->feat->dev_spinlock);
return scnprintf(buf, PAGE_SIZE, "%lld\n", val);
+}
+static ssize_t cs_cfg_param_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
struct cs_cfg_parameter *param = (struct cs_cfg_parameter *)eattr->var;
u64 val;
spin_lock(param->feat->dev_spinlock);
if (!kstrtoull(buf, 0, &val)) {
Same here.
param->current_value = val;
coresight_cfg_init_reg_param(param);
}
spin_unlock(param->feat->dev_spinlock);
return size;
+}
+static struct attribute * +cs_cfg_sysfs_create_feat_attr(struct device *dev, struct cs_cfg_feature *feat,
struct feat_attr_info *info)
+{
struct dev_ext_attribute *eattr;
eattr = devm_kzalloc(dev, sizeof(struct dev_ext_attribute),
GFP_KERNEL);
if (!eattr)
return NULL;
For concistency I would have expected a space here, as it is in cs_cfg_sysfs_create_param_attr().
eattr->attr.attr.name = devm_kstrdup(dev, info->name, GFP_KERNEL);
eattr->attr.attr.mode = info->store ? 0644 : 0444;
eattr->attr.show = info->show;
eattr->attr.store = info->store;
eattr->var = feat;
return &eattr->attr.attr;
+}
+static struct attribute * +cs_cfg_sysfs_create_param_attr(struct device *dev, const char *name,
struct cs_cfg_parameter *param)
+{
struct dev_ext_attribute *eattr;
eattr = devm_kzalloc(dev, sizeof(struct dev_ext_attribute),
GFP_KERNEL);
if (!eattr)
return NULL;
eattr->attr.attr.name = devm_kstrdup(dev, name, GFP_KERNEL);
eattr->attr.attr.mode = 0644;
eattr->attr.show = cs_cfg_param_show;
eattr->attr.store = cs_cfg_param_store;
eattr->var = param;
return &eattr->attr.attr;
+}
+int coresight_cfg_sysfs_add_grp(struct cs_cfg_feature *feat) +{
int p, attr_idx = 0;
struct attribute **attrs;
const char *name;
struct feat_attr_info *info;
struct device *dev = feat->csdev->dev.parent;
/* create sysfs group in csdev */
feat->param_group = devm_kzalloc(dev, sizeof(struct attribute_group),
GFP_KERNEL);
if (!feat->param_group)
return -ENOMEM;
feat->param_group->name = devm_kasprintf(dev, GFP_KERNEL, "%s.feat",
feat->desc->name);
if (!feat->param_group->name)
return -ENOMEM;
/* attributes - nr_params + enable + desc */
attrs = devm_kcalloc(dev, feat->nr_params + 2,
sizeof(struct attribute *), GFP_KERNEL);
@attrs needs to be NULL terminated and I'm surprised it hasn't blown up in your face yet (or I've missed the NULL terminated slot).
if (!attrs)
return -ENOMEM;
/* create base attributes in group */
while (feature_std_attr[attr_idx].name) {
info = &feature_std_attr[attr_idx];
attrs[attr_idx] = cs_cfg_sysfs_create_feat_attr(dev, feat,
info);
if (!attrs[attr_idx])
return -ENOMEM;
attr_idx++;
}
/* create params in group */
for (p = 0; p < feat->nr_params; p++) {
name = feat->desc->params[p].name;
attrs[attr_idx] =
cs_cfg_sysfs_create_param_attr(dev, name,
&feat->params[p]);
attrs[attr_idx] = cs_cfg_sysfs_create_param_attr(dev, name, &feat->params[p]);
if (!attrs[attr_idx])
return -ENOMEM;
attr_idx++;
}
feat->param_group->attrs = attrs;
return sysfs_create_group(&feat->csdev->dev.kobj, feat->param_group);
+} +EXPORT_SYMBOL_GPL(coresight_cfg_sysfs_add_grp);
+/*
- standard routines to set/save/reset enabled features, and iterate
- groups of features on a device.
- */
+void coresight_cfg_list_add_feat(struct cs_cfg_feature *feat) +{
spin_lock(&feat->csdev->cfg_lock);
list_add(&feat->node, &feat->csdev->feat_list);
spin_unlock(&feat->csdev->cfg_lock);
+} +EXPORT_SYMBOL_GPL(coresight_cfg_list_add_feat);
+static void coresight_cfg_set_reg(struct cs_cfg_reg *reg, u32 flags) +{
u32 *p_val32 = (u32 *)reg->drv_store;
u32 tmp32;
if (!(flags & CS_CFG_REG_VAL_64BIT)) {
if (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;
+}
+static void coresight_cfg_save_reg(struct cs_cfg_reg *reg, u32 flags) +{
if (flags & CS_CFG_REG_VAL_64BIT)
reg->value.val64 = *(u64 *)(reg->drv_store);
else
reg->value.val32 = *(u32 *)(reg->drv_store);
+}
+static void coresight_cfg_init_reg(struct cs_cfg_reg *reg,
const struct cs_cfg_reg_desc *desc)
Indentation problem.
It is hard to look a the rest of this patch without more context. As such I will come back to it as I look a the other patches in this series.
Thanks, Mathieu
+{
reg->value.val64 = desc->value.val64;
+}
+static void coresight_cfg_init_reg_param(struct cs_cfg_parameter *param) +{
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 cs_cfg_set_on_enable(struct cs_cfg_feature *feat, const bool force_set) +{
int i;
u32 flags;
spin_lock(feat->dev_spinlock);
if (feat->enabled || force_set) {
for (i = 0; i < feat->nr_regs; i++) {
flags = feat->desc->regs[i].flags;
coresight_cfg_set_reg(&feat->regs[i], flags);
}
}
dev_dbg(&feat->csdev->dev, "Feature %s: %s", feat->desc->name,
feat->enabled || force_set ? "Set enabled" : "Skip disabled");
spin_unlock(feat->dev_spinlock);
return 0;
+}
+static void cs_cfg_save_on_disable(struct cs_cfg_feature *feat, const bool force_save) +{
int i;
u32 flags;
spin_lock(feat->dev_spinlock);
if (feat->enabled || force_save) {
for (i = 0; i < feat->nr_regs; i++) {
flags = feat->desc->regs[i].flags;
if (flags & CS_CFG_REG_VAL_SAVE)
coresight_cfg_save_reg(&feat->regs[i], flags);
}
}
dev_dbg(&feat->csdev->dev, "Feature %s: %s", feat->desc->name,
feat->enabled || force_save ? "Save disabled" : "Skip disabled");
spin_unlock(feat->dev_spinlock);
+}
+/* default reset - restore default values, disable feature */ +static void cs_cfg_reset_feat(struct cs_cfg_feature *feat) +{
const struct cs_cfg_feature_desc *feat_desc = feat->desc;
struct cs_cfg_reg_desc *reg_desc;
struct cs_cfg_parameter *param;
struct cs_cfg_reg *reg;
int i;
u32 flags;
spin_lock(feat->dev_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];
flags = reg_desc->flags;
reg = &feat->regs[i];
/* check if reg set from a parameter otherwise desc default */
if (flags & CS_CFG_REG_VAL_PARAM) {
param = &feat->params[reg_desc->value.val32];
param->reg = reg;
param->val64 = flags & CS_CFG_REG_VAL_64BIT;
coresight_cfg_init_reg_param(param);
} else
coresight_cfg_init_reg(reg, reg_desc);
}
spin_unlock(feat->dev_spinlock);
+}
+void coresight_cfg_set_def_ops(struct cs_cfg_feature *feat) +{
feat->ops.set_on_enable = cs_cfg_set_on_enable;
feat->ops.save_on_disable = cs_cfg_save_on_disable;
feat->ops.reset = cs_cfg_reset_feat;
+} +EXPORT_SYMBOL_GPL(coresight_cfg_set_def_ops);
+int coresight_cfg_set_enabled_feats(struct coresight_device *csdev) +{
struct cs_cfg_feature *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(coresight_cfg_set_enabled_feats);
+void coresight_cfg_save_enabled_feats(struct coresight_device *csdev) +{
struct cs_cfg_feature *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(coresight_cfg_save_enabled_feats);
+void coresight_cfg_reset_feats(struct coresight_device *csdev) +{
struct cs_cfg_feature *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(coresight_cfg_reset_feats);
+static int coresight_cfg_update_presets(struct cs_cfg_config_dev *cfg, int preset) +{
int i, j, line_offset = 0, val_idx = 0, max_idx;
u64 val;
struct cs_cfg_feature *feat;
struct cs_cfg_parameter *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->dev_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->dev_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 coresight_cfg_update_curr_params(struct cs_cfg_config_dev *cfg) +{
int i, j;
struct cs_cfg_feature *feat;
struct cs_cfg_parameter *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->dev_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->dev_spinlock);
}
}
return 0;
+}
+static int coresight_cfg_prog_config(struct cs_cfg_config_dev *cfg, bool enable) +{
int i, err = 0;
struct cs_cfg_feature *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 coresight_cfg_enable_dev_config(struct coresight_device *csdev,
unsigned long cfg_id,
int preset)
+{
struct cs_cfg_config_dev *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 = coresight_cfg_update_presets(cfg, preset);
else
err = coresight_cfg_update_curr_params(cfg);
if (!err)
err = coresight_cfg_prog_config(cfg, true);
if (!err)
cfg->enabled = true;
break;
}
}
spin_unlock(&csdev->cfg_lock);
return err;
+} +EXPORT_SYMBOL_GPL(coresight_cfg_enable_dev_config);
+void coresight_cfg_disable_dev_config(struct coresight_device *csdev) +{
struct cs_cfg_config_dev *cfg;
spin_lock(&csdev->cfg_lock);
list_for_each_entry(cfg, &csdev->syscfg_list, node) {
if (cfg->enabled) {
coresight_cfg_prog_config(cfg, false);
cfg->enabled = false;
}
}
spin_unlock(&csdev->cfg_lock);
+} +EXPORT_SYMBOL_GPL(coresight_cfg_disable_dev_config); diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 949a078c4692..afecab88451a 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -270,4 +270,20 @@ struct cs_cfg_dev_feat_ops { const struct cs_cfg_feature_desc *feat_desc); };
+/* coresight config API functions */
+/* helper functions for feature manipulation */ +int coresight_cfg_sysfs_add_grp(struct cs_cfg_feature *feat); +void coresight_cfg_set_def_ops(struct cs_cfg_feature *feat); +void coresight_cfg_list_add_feat(struct cs_cfg_feature *feat);
+/* enable / disable features or configs on a device */ +int coresight_cfg_set_enabled_feats(struct coresight_device *csdev); +void coresight_cfg_save_enabled_feats(struct coresight_device *csdev); +void coresight_cfg_reset_feats(struct coresight_device *csdev); +int coresight_cfg_enable_dev_config(struct coresight_device *csdev,
unsigned long cfg_id,
int preset);
+void coresight_cfg_disable_dev_config(struct coresight_device *csdev);
#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */
2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
Hi Mathieu,
On Fri, 30 Oct 2020 at 17:02, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Thu, Oct 29, 2020 at 06:31:53PM +0000, Mike Leach wrote:
Hi Mathieu, Thanks for looking at this.
However, per your comment in the v1 set, for the next set I have moved management of features out of individual coresight device sysfs, and into a custom configfs directory. This actually makes things easter for the user - they can change a single parameter value and have it change on all device instances of the feature.
Are you pointing out the comments I made in this patch no longer apply because you have changed your design? Have I understood you correctly?
In effect - yes. The design has evolved - and I believe for the better.
In your review of v1 of this set, you expressed a preference for most of the sysfs to be moved to configfs, with some minimal functionality remaining in sysfs. At this point features were adjusted on a per device basis via sysfs - if you have 4 ETMs, there are 4 devices to adjust.
At the time of v2 I hadn't managed to find a credible alternative within configfs that worked. While configfs and sysfs are superficially similar, there are key differences that make configfs far less feature rich than sysfs. With my subsequent work on configfs I did eventually come up with a scheme that let the feature parameters be altered in configfs (as you will see in v3 of the set). This isn't without a certain amount of compromise, so we will see if it is acceptable.
The advantage of the configfs solution, is that a single location will adjust the parameters for all instances of the device.
So if we take the case of the built-in example of strobing - which is where we have existing users with non-upstream patches that hardwire the algorithm into the driver.
In set v2 - a user has a script that will adjust the values of the strobing parameters window and period for each ETM instance in their system, using a script. Running perf then picks up these values on any ETM it happens to schedule trace on. Now with v3, a user changes one location in configfs and running perf will pick up the values on any ETM it happens to schedule trace on. - effectively eliminating the need for the script.
What we lose with the configfs solution is the ability to change just a single instance of the ETM using the feature. But this isn't the way these features are used.
So I had a choice of adding the configfs solution in parallel with the sysfs solution, or withdrawing the sysfs solution to leave configfs as the only way control.
In the circumstances I felt that the best solution was to drop the sysfs support for now. I couldn't see a good reason to have two locations to change the same thing. Should anyone come up with a credible reason it needs to come back then I can re-add it, taking account of the issue you raise.
I do believe that the configfs solution is the better one, which does mean that I have spent time developing something that ultimately will not be used, and unfortunately you have spent time reviewing it.
Regards
Mike
Regards
Mike
On Fri, 9 Oct 2020 at 22:34, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Thu, Aug 27, 2020 at 03:34:07PM +0100, 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 | 565 ++++++++++++++++++ .../hwtracing/coresight/coresight-config.h | 16 + 3 files changed, 582 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 3605dd770664..177bc6338312 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..96f8df59df58 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.c @@ -0,0 +1,565 @@ +// 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"
+static void coresight_cfg_init_reg_param(struct cs_cfg_parameter *param);
+/*
- Handlers for creating and manipulating the feature representation
- in sysfs.
- */
+/* base feature attribute info */ +struct feat_attr_info {
const char *name;
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
+};
+static ssize_t cs_cfg_enable_show(struct device *dev,
struct device_attribute *attr,
char *buf)
There is no need to have "char *buf" on a line by itself. Same for cs_cfg_param_show().
+{
struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
struct cs_cfg_feature *feat = (struct cs_cfg_feature *)eattr->var;
int val;
spin_lock(feat->dev_spinlock);
I would rename cs_cfg_featre::dev_spinlock to cs_cfg_feature::csdev_spinlock to remove any ambiguity.
val = feat->enabled;
spin_unlock(feat->dev_spinlock);
return scnprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+static ssize_t cs_cfg_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
struct cs_cfg_feature *feat = (struct cs_cfg_feature *)eattr->var;
int val;
spin_lock(feat->dev_spinlock);
if (!kstrtoint(buf, 0, &val))
Please call kstrtoint() outside of the lock.
feat->enabled = val;
spin_unlock(feat->dev_spinlock);
return size;
+}
+static ssize_t cs_cfg_desc_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
struct cs_cfg_feature *feat = (struct cs_cfg_feature *)eattr->var;
return scnprintf(buf, PAGE_SIZE, "%s\n", feat->desc->brief);
+}
+struct feat_attr_info feature_std_attr[] = {
{
.name = "enable",
.show = cs_cfg_enable_show,
.store = cs_cfg_enable_store,
},
{
.name = "description",
.show = cs_cfg_desc_show,
},
{ 0 },
+};
+static ssize_t cs_cfg_param_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
struct cs_cfg_parameter *param = (struct cs_cfg_parameter *)eattr->var;
u64 val;
spin_lock(param->feat->dev_spinlock);
val = param->current_value;
spin_unlock(param->feat->dev_spinlock);
return scnprintf(buf, PAGE_SIZE, "%lld\n", val);
+}
+static ssize_t cs_cfg_param_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
struct cs_cfg_parameter *param = (struct cs_cfg_parameter *)eattr->var;
u64 val;
spin_lock(param->feat->dev_spinlock);
if (!kstrtoull(buf, 0, &val)) {
Same here.
param->current_value = val;
coresight_cfg_init_reg_param(param);
}
spin_unlock(param->feat->dev_spinlock);
return size;
+}
+static struct attribute * +cs_cfg_sysfs_create_feat_attr(struct device *dev, struct cs_cfg_feature *feat,
struct feat_attr_info *info)
+{
struct dev_ext_attribute *eattr;
eattr = devm_kzalloc(dev, sizeof(struct dev_ext_attribute),
GFP_KERNEL);
if (!eattr)
return NULL;
For concistency I would have expected a space here, as it is in cs_cfg_sysfs_create_param_attr().
eattr->attr.attr.name = devm_kstrdup(dev, info->name, GFP_KERNEL);
eattr->attr.attr.mode = info->store ? 0644 : 0444;
eattr->attr.show = info->show;
eattr->attr.store = info->store;
eattr->var = feat;
return &eattr->attr.attr;
+}
+static struct attribute * +cs_cfg_sysfs_create_param_attr(struct device *dev, const char *name,
struct cs_cfg_parameter *param)
+{
struct dev_ext_attribute *eattr;
eattr = devm_kzalloc(dev, sizeof(struct dev_ext_attribute),
GFP_KERNEL);
if (!eattr)
return NULL;
eattr->attr.attr.name = devm_kstrdup(dev, name, GFP_KERNEL);
eattr->attr.attr.mode = 0644;
eattr->attr.show = cs_cfg_param_show;
eattr->attr.store = cs_cfg_param_store;
eattr->var = param;
return &eattr->attr.attr;
+}
+int coresight_cfg_sysfs_add_grp(struct cs_cfg_feature *feat) +{
int p, attr_idx = 0;
struct attribute **attrs;
const char *name;
struct feat_attr_info *info;
struct device *dev = feat->csdev->dev.parent;
/* create sysfs group in csdev */
feat->param_group = devm_kzalloc(dev, sizeof(struct attribute_group),
GFP_KERNEL);
if (!feat->param_group)
return -ENOMEM;
feat->param_group->name = devm_kasprintf(dev, GFP_KERNEL, "%s.feat",
feat->desc->name);
if (!feat->param_group->name)
return -ENOMEM;
/* attributes - nr_params + enable + desc */
attrs = devm_kcalloc(dev, feat->nr_params + 2,
sizeof(struct attribute *), GFP_KERNEL);
@attrs needs to be NULL terminated and I'm surprised it hasn't blown up in your face yet (or I've missed the NULL terminated slot).
if (!attrs)
return -ENOMEM;
/* create base attributes in group */
while (feature_std_attr[attr_idx].name) {
info = &feature_std_attr[attr_idx];
attrs[attr_idx] = cs_cfg_sysfs_create_feat_attr(dev, feat,
info);
if (!attrs[attr_idx])
return -ENOMEM;
attr_idx++;
}
/* create params in group */
for (p = 0; p < feat->nr_params; p++) {
name = feat->desc->params[p].name;
attrs[attr_idx] =
cs_cfg_sysfs_create_param_attr(dev, name,
&feat->params[p]);
attrs[attr_idx] = cs_cfg_sysfs_create_param_attr(dev, name, &feat->params[p]);
if (!attrs[attr_idx])
return -ENOMEM;
attr_idx++;
}
feat->param_group->attrs = attrs;
return sysfs_create_group(&feat->csdev->dev.kobj, feat->param_group);
+} +EXPORT_SYMBOL_GPL(coresight_cfg_sysfs_add_grp);
+/*
- standard routines to set/save/reset enabled features, and iterate
- groups of features on a device.
- */
+void coresight_cfg_list_add_feat(struct cs_cfg_feature *feat) +{
spin_lock(&feat->csdev->cfg_lock);
list_add(&feat->node, &feat->csdev->feat_list);
spin_unlock(&feat->csdev->cfg_lock);
+} +EXPORT_SYMBOL_GPL(coresight_cfg_list_add_feat);
+static void coresight_cfg_set_reg(struct cs_cfg_reg *reg, u32 flags) +{
u32 *p_val32 = (u32 *)reg->drv_store;
u32 tmp32;
if (!(flags & CS_CFG_REG_VAL_64BIT)) {
if (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;
+}
+static void coresight_cfg_save_reg(struct cs_cfg_reg *reg, u32 flags) +{
if (flags & CS_CFG_REG_VAL_64BIT)
reg->value.val64 = *(u64 *)(reg->drv_store);
else
reg->value.val32 = *(u32 *)(reg->drv_store);
+}
+static void coresight_cfg_init_reg(struct cs_cfg_reg *reg,
const struct cs_cfg_reg_desc *desc)
Indentation problem.
It is hard to look a the rest of this patch without more context. As such I will come back to it as I look a the other patches in this series.
Thanks, Mathieu
+{
reg->value.val64 = desc->value.val64;
+}
+static void coresight_cfg_init_reg_param(struct cs_cfg_parameter *param) +{
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 cs_cfg_set_on_enable(struct cs_cfg_feature *feat, const bool force_set) +{
int i;
u32 flags;
spin_lock(feat->dev_spinlock);
if (feat->enabled || force_set) {
for (i = 0; i < feat->nr_regs; i++) {
flags = feat->desc->regs[i].flags;
coresight_cfg_set_reg(&feat->regs[i], flags);
}
}
dev_dbg(&feat->csdev->dev, "Feature %s: %s", feat->desc->name,
feat->enabled || force_set ? "Set enabled" : "Skip disabled");
spin_unlock(feat->dev_spinlock);
return 0;
+}
+static void cs_cfg_save_on_disable(struct cs_cfg_feature *feat, const bool force_save) +{
int i;
u32 flags;
spin_lock(feat->dev_spinlock);
if (feat->enabled || force_save) {
for (i = 0; i < feat->nr_regs; i++) {
flags = feat->desc->regs[i].flags;
if (flags & CS_CFG_REG_VAL_SAVE)
coresight_cfg_save_reg(&feat->regs[i], flags);
}
}
dev_dbg(&feat->csdev->dev, "Feature %s: %s", feat->desc->name,
feat->enabled || force_save ? "Save disabled" : "Skip disabled");
spin_unlock(feat->dev_spinlock);
+}
+/* default reset - restore default values, disable feature */ +static void cs_cfg_reset_feat(struct cs_cfg_feature *feat) +{
const struct cs_cfg_feature_desc *feat_desc = feat->desc;
struct cs_cfg_reg_desc *reg_desc;
struct cs_cfg_parameter *param;
struct cs_cfg_reg *reg;
int i;
u32 flags;
spin_lock(feat->dev_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];
flags = reg_desc->flags;
reg = &feat->regs[i];
/* check if reg set from a parameter otherwise desc default */
if (flags & CS_CFG_REG_VAL_PARAM) {
param = &feat->params[reg_desc->value.val32];
param->reg = reg;
param->val64 = flags & CS_CFG_REG_VAL_64BIT;
coresight_cfg_init_reg_param(param);
} else
coresight_cfg_init_reg(reg, reg_desc);
}
spin_unlock(feat->dev_spinlock);
+}
+void coresight_cfg_set_def_ops(struct cs_cfg_feature *feat) +{
feat->ops.set_on_enable = cs_cfg_set_on_enable;
feat->ops.save_on_disable = cs_cfg_save_on_disable;
feat->ops.reset = cs_cfg_reset_feat;
+} +EXPORT_SYMBOL_GPL(coresight_cfg_set_def_ops);
+int coresight_cfg_set_enabled_feats(struct coresight_device *csdev) +{
struct cs_cfg_feature *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(coresight_cfg_set_enabled_feats);
+void coresight_cfg_save_enabled_feats(struct coresight_device *csdev) +{
struct cs_cfg_feature *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(coresight_cfg_save_enabled_feats);
+void coresight_cfg_reset_feats(struct coresight_device *csdev) +{
struct cs_cfg_feature *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(coresight_cfg_reset_feats);
+static int coresight_cfg_update_presets(struct cs_cfg_config_dev *cfg, int preset) +{
int i, j, line_offset = 0, val_idx = 0, max_idx;
u64 val;
struct cs_cfg_feature *feat;
struct cs_cfg_parameter *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->dev_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->dev_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 coresight_cfg_update_curr_params(struct cs_cfg_config_dev *cfg) +{
int i, j;
struct cs_cfg_feature *feat;
struct cs_cfg_parameter *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->dev_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->dev_spinlock);
}
}
return 0;
+}
+static int coresight_cfg_prog_config(struct cs_cfg_config_dev *cfg, bool enable) +{
int i, err = 0;
struct cs_cfg_feature *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 coresight_cfg_enable_dev_config(struct coresight_device *csdev,
unsigned long cfg_id,
int preset)
+{
struct cs_cfg_config_dev *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 = coresight_cfg_update_presets(cfg, preset);
else
err = coresight_cfg_update_curr_params(cfg);
if (!err)
err = coresight_cfg_prog_config(cfg, true);
if (!err)
cfg->enabled = true;
break;
}
}
spin_unlock(&csdev->cfg_lock);
return err;
+} +EXPORT_SYMBOL_GPL(coresight_cfg_enable_dev_config);
+void coresight_cfg_disable_dev_config(struct coresight_device *csdev) +{
struct cs_cfg_config_dev *cfg;
spin_lock(&csdev->cfg_lock);
list_for_each_entry(cfg, &csdev->syscfg_list, node) {
if (cfg->enabled) {
coresight_cfg_prog_config(cfg, false);
cfg->enabled = false;
}
}
spin_unlock(&csdev->cfg_lock);
+} +EXPORT_SYMBOL_GPL(coresight_cfg_disable_dev_config); diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 949a078c4692..afecab88451a 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -270,4 +270,20 @@ struct cs_cfg_dev_feat_ops { const struct cs_cfg_feature_desc *feat_desc); };
+/* coresight config API functions */
+/* helper functions for feature manipulation */ +int coresight_cfg_sysfs_add_grp(struct cs_cfg_feature *feat); +void coresight_cfg_set_def_ops(struct cs_cfg_feature *feat); +void coresight_cfg_list_add_feat(struct cs_cfg_feature *feat);
+/* enable / disable features or configs on a device */ +int coresight_cfg_set_enabled_feats(struct coresight_device *csdev); +void coresight_cfg_save_enabled_feats(struct coresight_device *csdev); +void coresight_cfg_reset_feats(struct coresight_device *csdev); +int coresight_cfg_enable_dev_config(struct coresight_device *csdev,
unsigned long cfg_id,
int preset);
+void coresight_cfg_disable_dev_config(struct coresight_device *csdev);
#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */
2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
Good morning,
On Fri, Oct 30, 2020 at 11:02:05PM +0000, Mike Leach wrote:
Hi Mathieu,
On Fri, 30 Oct 2020 at 17:02, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Thu, Oct 29, 2020 at 06:31:53PM +0000, Mike Leach wrote:
Hi Mathieu, Thanks for looking at this.
However, per your comment in the v1 set, for the next set I have moved management of features out of individual coresight device sysfs, and into a custom configfs directory. This actually makes things easter for the user - they can change a single parameter value and have it change on all device instances of the feature.
Are you pointing out the comments I made in this patch no longer apply because you have changed your design? Have I understood you correctly?
In effect - yes. The design has evolved - and I believe for the better.
In your review of v1 of this set, you expressed a preference for most of the sysfs to be moved to configfs, with some minimal functionality remaining in sysfs. At this point features were adjusted on a per device basis via sysfs - if you have 4 ETMs, there are 4 devices to adjust.
At the time of v2 I hadn't managed to find a credible alternative within configfs that worked. While configfs and sysfs are superficially similar, there are key differences that make configfs far less feature rich than sysfs. With my subsequent work on configfs I did eventually come up with a scheme that let the feature parameters be altered in configfs (as you will see in v3 of the set). This isn't without a certain amount of compromise, so we will see if it is acceptable.
The advantage of the configfs solution, is that a single location will adjust the parameters for all instances of the device.
So if we take the case of the built-in example of strobing - which is where we have existing users with non-upstream patches that hardwire the algorithm into the driver.
In set v2 - a user has a script that will adjust the values of the strobing parameters window and period for each ETM instance in their system, using a script. Running perf then picks up these values on any ETM it happens to schedule trace on. Now with v3, a user changes one location in configfs and running perf will pick up the values on any ETM it happens to schedule trace on. - effectively eliminating the need for the script.
What we lose with the configfs solution is the ability to change just a single instance of the ETM using the feature. But this isn't the way these features are used.
So I had a choice of adding the configfs solution in parallel with the sysfs solution, or withdrawing the sysfs solution to leave configfs as the only way control.
In the circumstances I felt that the best solution was to drop the sysfs support for now. I couldn't see a good reason to have two locations to change the same thing. Should anyone come up with a credible reason it needs to come back then I can re-add it, taking account of the issue you raise.
I do believe that the configfs solution is the better one, which does mean that I have spent time developing something that ultimately will not be used, and unfortunately you have spent time reviewing it.
I'm in total agreement with everything you wrote above.
With regards to time spent on code that won't be used (either writing or reviewing it), that is simply part of working upstream. It is also inherent to the process of finding an optimal solution.
I received your V3 but Suzuki sqeezed in his patchset on system instructions just before yours. As such I won't be able to start looking at it right away but I guarantee it won't take as long as it took for V2.
Mathieu
Regards
Mike
Regards
Mike
On Fri, 9 Oct 2020 at 22:34, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Thu, Aug 27, 2020 at 03:34:07PM +0100, 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 | 565 ++++++++++++++++++ .../hwtracing/coresight/coresight-config.h | 16 + 3 files changed, 582 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 3605dd770664..177bc6338312 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..96f8df59df58 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.c @@ -0,0 +1,565 @@ +// 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"
+static void coresight_cfg_init_reg_param(struct cs_cfg_parameter *param);
+/*
- Handlers for creating and manipulating the feature representation
- in sysfs.
- */
+/* base feature attribute info */ +struct feat_attr_info {
const char *name;
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
+};
+static ssize_t cs_cfg_enable_show(struct device *dev,
struct device_attribute *attr,
char *buf)
There is no need to have "char *buf" on a line by itself. Same for cs_cfg_param_show().
+{
struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
struct cs_cfg_feature *feat = (struct cs_cfg_feature *)eattr->var;
int val;
spin_lock(feat->dev_spinlock);
I would rename cs_cfg_featre::dev_spinlock to cs_cfg_feature::csdev_spinlock to remove any ambiguity.
val = feat->enabled;
spin_unlock(feat->dev_spinlock);
return scnprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+static ssize_t cs_cfg_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
struct cs_cfg_feature *feat = (struct cs_cfg_feature *)eattr->var;
int val;
spin_lock(feat->dev_spinlock);
if (!kstrtoint(buf, 0, &val))
Please call kstrtoint() outside of the lock.
feat->enabled = val;
spin_unlock(feat->dev_spinlock);
return size;
+}
+static ssize_t cs_cfg_desc_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
struct cs_cfg_feature *feat = (struct cs_cfg_feature *)eattr->var;
return scnprintf(buf, PAGE_SIZE, "%s\n", feat->desc->brief);
+}
+struct feat_attr_info feature_std_attr[] = {
{
.name = "enable",
.show = cs_cfg_enable_show,
.store = cs_cfg_enable_store,
},
{
.name = "description",
.show = cs_cfg_desc_show,
},
{ 0 },
+};
+static ssize_t cs_cfg_param_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
struct cs_cfg_parameter *param = (struct cs_cfg_parameter *)eattr->var;
u64 val;
spin_lock(param->feat->dev_spinlock);
val = param->current_value;
spin_unlock(param->feat->dev_spinlock);
return scnprintf(buf, PAGE_SIZE, "%lld\n", val);
+}
+static ssize_t cs_cfg_param_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
struct dev_ext_attribute *eattr =
container_of(attr, struct dev_ext_attribute, attr);
struct cs_cfg_parameter *param = (struct cs_cfg_parameter *)eattr->var;
u64 val;
spin_lock(param->feat->dev_spinlock);
if (!kstrtoull(buf, 0, &val)) {
Same here.
param->current_value = val;
coresight_cfg_init_reg_param(param);
}
spin_unlock(param->feat->dev_spinlock);
return size;
+}
+static struct attribute * +cs_cfg_sysfs_create_feat_attr(struct device *dev, struct cs_cfg_feature *feat,
struct feat_attr_info *info)
+{
struct dev_ext_attribute *eattr;
eattr = devm_kzalloc(dev, sizeof(struct dev_ext_attribute),
GFP_KERNEL);
if (!eattr)
return NULL;
For concistency I would have expected a space here, as it is in cs_cfg_sysfs_create_param_attr().
eattr->attr.attr.name = devm_kstrdup(dev, info->name, GFP_KERNEL);
eattr->attr.attr.mode = info->store ? 0644 : 0444;
eattr->attr.show = info->show;
eattr->attr.store = info->store;
eattr->var = feat;
return &eattr->attr.attr;
+}
+static struct attribute * +cs_cfg_sysfs_create_param_attr(struct device *dev, const char *name,
struct cs_cfg_parameter *param)
+{
struct dev_ext_attribute *eattr;
eattr = devm_kzalloc(dev, sizeof(struct dev_ext_attribute),
GFP_KERNEL);
if (!eattr)
return NULL;
eattr->attr.attr.name = devm_kstrdup(dev, name, GFP_KERNEL);
eattr->attr.attr.mode = 0644;
eattr->attr.show = cs_cfg_param_show;
eattr->attr.store = cs_cfg_param_store;
eattr->var = param;
return &eattr->attr.attr;
+}
+int coresight_cfg_sysfs_add_grp(struct cs_cfg_feature *feat) +{
int p, attr_idx = 0;
struct attribute **attrs;
const char *name;
struct feat_attr_info *info;
struct device *dev = feat->csdev->dev.parent;
/* create sysfs group in csdev */
feat->param_group = devm_kzalloc(dev, sizeof(struct attribute_group),
GFP_KERNEL);
if (!feat->param_group)
return -ENOMEM;
feat->param_group->name = devm_kasprintf(dev, GFP_KERNEL, "%s.feat",
feat->desc->name);
if (!feat->param_group->name)
return -ENOMEM;
/* attributes - nr_params + enable + desc */
attrs = devm_kcalloc(dev, feat->nr_params + 2,
sizeof(struct attribute *), GFP_KERNEL);
@attrs needs to be NULL terminated and I'm surprised it hasn't blown up in your face yet (or I've missed the NULL terminated slot).
if (!attrs)
return -ENOMEM;
/* create base attributes in group */
while (feature_std_attr[attr_idx].name) {
info = &feature_std_attr[attr_idx];
attrs[attr_idx] = cs_cfg_sysfs_create_feat_attr(dev, feat,
info);
if (!attrs[attr_idx])
return -ENOMEM;
attr_idx++;
}
/* create params in group */
for (p = 0; p < feat->nr_params; p++) {
name = feat->desc->params[p].name;
attrs[attr_idx] =
cs_cfg_sysfs_create_param_attr(dev, name,
&feat->params[p]);
attrs[attr_idx] = cs_cfg_sysfs_create_param_attr(dev, name, &feat->params[p]);
if (!attrs[attr_idx])
return -ENOMEM;
attr_idx++;
}
feat->param_group->attrs = attrs;
return sysfs_create_group(&feat->csdev->dev.kobj, feat->param_group);
+} +EXPORT_SYMBOL_GPL(coresight_cfg_sysfs_add_grp);
+/*
- standard routines to set/save/reset enabled features, and iterate
- groups of features on a device.
- */
+void coresight_cfg_list_add_feat(struct cs_cfg_feature *feat) +{
spin_lock(&feat->csdev->cfg_lock);
list_add(&feat->node, &feat->csdev->feat_list);
spin_unlock(&feat->csdev->cfg_lock);
+} +EXPORT_SYMBOL_GPL(coresight_cfg_list_add_feat);
+static void coresight_cfg_set_reg(struct cs_cfg_reg *reg, u32 flags) +{
u32 *p_val32 = (u32 *)reg->drv_store;
u32 tmp32;
if (!(flags & CS_CFG_REG_VAL_64BIT)) {
if (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;
+}
+static void coresight_cfg_save_reg(struct cs_cfg_reg *reg, u32 flags) +{
if (flags & CS_CFG_REG_VAL_64BIT)
reg->value.val64 = *(u64 *)(reg->drv_store);
else
reg->value.val32 = *(u32 *)(reg->drv_store);
+}
+static void coresight_cfg_init_reg(struct cs_cfg_reg *reg,
const struct cs_cfg_reg_desc *desc)
Indentation problem.
It is hard to look a the rest of this patch without more context. As such I will come back to it as I look a the other patches in this series.
Thanks, Mathieu
+{
reg->value.val64 = desc->value.val64;
+}
+static void coresight_cfg_init_reg_param(struct cs_cfg_parameter *param) +{
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 cs_cfg_set_on_enable(struct cs_cfg_feature *feat, const bool force_set) +{
int i;
u32 flags;
spin_lock(feat->dev_spinlock);
if (feat->enabled || force_set) {
for (i = 0; i < feat->nr_regs; i++) {
flags = feat->desc->regs[i].flags;
coresight_cfg_set_reg(&feat->regs[i], flags);
}
}
dev_dbg(&feat->csdev->dev, "Feature %s: %s", feat->desc->name,
feat->enabled || force_set ? "Set enabled" : "Skip disabled");
spin_unlock(feat->dev_spinlock);
return 0;
+}
+static void cs_cfg_save_on_disable(struct cs_cfg_feature *feat, const bool force_save) +{
int i;
u32 flags;
spin_lock(feat->dev_spinlock);
if (feat->enabled || force_save) {
for (i = 0; i < feat->nr_regs; i++) {
flags = feat->desc->regs[i].flags;
if (flags & CS_CFG_REG_VAL_SAVE)
coresight_cfg_save_reg(&feat->regs[i], flags);
}
}
dev_dbg(&feat->csdev->dev, "Feature %s: %s", feat->desc->name,
feat->enabled || force_save ? "Save disabled" : "Skip disabled");
spin_unlock(feat->dev_spinlock);
+}
+/* default reset - restore default values, disable feature */ +static void cs_cfg_reset_feat(struct cs_cfg_feature *feat) +{
const struct cs_cfg_feature_desc *feat_desc = feat->desc;
struct cs_cfg_reg_desc *reg_desc;
struct cs_cfg_parameter *param;
struct cs_cfg_reg *reg;
int i;
u32 flags;
spin_lock(feat->dev_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];
flags = reg_desc->flags;
reg = &feat->regs[i];
/* check if reg set from a parameter otherwise desc default */
if (flags & CS_CFG_REG_VAL_PARAM) {
param = &feat->params[reg_desc->value.val32];
param->reg = reg;
param->val64 = flags & CS_CFG_REG_VAL_64BIT;
coresight_cfg_init_reg_param(param);
} else
coresight_cfg_init_reg(reg, reg_desc);
}
spin_unlock(feat->dev_spinlock);
+}
+void coresight_cfg_set_def_ops(struct cs_cfg_feature *feat) +{
feat->ops.set_on_enable = cs_cfg_set_on_enable;
feat->ops.save_on_disable = cs_cfg_save_on_disable;
feat->ops.reset = cs_cfg_reset_feat;
+} +EXPORT_SYMBOL_GPL(coresight_cfg_set_def_ops);
+int coresight_cfg_set_enabled_feats(struct coresight_device *csdev) +{
struct cs_cfg_feature *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(coresight_cfg_set_enabled_feats);
+void coresight_cfg_save_enabled_feats(struct coresight_device *csdev) +{
struct cs_cfg_feature *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(coresight_cfg_save_enabled_feats);
+void coresight_cfg_reset_feats(struct coresight_device *csdev) +{
struct cs_cfg_feature *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(coresight_cfg_reset_feats);
+static int coresight_cfg_update_presets(struct cs_cfg_config_dev *cfg, int preset) +{
int i, j, line_offset = 0, val_idx = 0, max_idx;
u64 val;
struct cs_cfg_feature *feat;
struct cs_cfg_parameter *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->dev_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->dev_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 coresight_cfg_update_curr_params(struct cs_cfg_config_dev *cfg) +{
int i, j;
struct cs_cfg_feature *feat;
struct cs_cfg_parameter *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->dev_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->dev_spinlock);
}
}
return 0;
+}
+static int coresight_cfg_prog_config(struct cs_cfg_config_dev *cfg, bool enable) +{
int i, err = 0;
struct cs_cfg_feature *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 coresight_cfg_enable_dev_config(struct coresight_device *csdev,
unsigned long cfg_id,
int preset)
+{
struct cs_cfg_config_dev *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 = coresight_cfg_update_presets(cfg, preset);
else
err = coresight_cfg_update_curr_params(cfg);
if (!err)
err = coresight_cfg_prog_config(cfg, true);
if (!err)
cfg->enabled = true;
break;
}
}
spin_unlock(&csdev->cfg_lock);
return err;
+} +EXPORT_SYMBOL_GPL(coresight_cfg_enable_dev_config);
+void coresight_cfg_disable_dev_config(struct coresight_device *csdev) +{
struct cs_cfg_config_dev *cfg;
spin_lock(&csdev->cfg_lock);
list_for_each_entry(cfg, &csdev->syscfg_list, node) {
if (cfg->enabled) {
coresight_cfg_prog_config(cfg, false);
cfg->enabled = false;
}
}
spin_unlock(&csdev->cfg_lock);
+} +EXPORT_SYMBOL_GPL(coresight_cfg_disable_dev_config); diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 949a078c4692..afecab88451a 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -270,4 +270,20 @@ struct cs_cfg_dev_feat_ops { const struct cs_cfg_feature_desc *feat_desc); };
+/* coresight config API functions */
+/* helper functions for feature manipulation */ +int coresight_cfg_sysfs_add_grp(struct cs_cfg_feature *feat); +void coresight_cfg_set_def_ops(struct cs_cfg_feature *feat); +void coresight_cfg_list_add_feat(struct cs_cfg_feature *feat);
+/* enable / disable features or configs on a device */ +int coresight_cfg_set_enabled_feats(struct coresight_device *csdev); +void coresight_cfg_save_enabled_feats(struct coresight_device *csdev); +void coresight_cfg_reset_feats(struct coresight_device *csdev); +int coresight_cfg_enable_dev_config(struct coresight_device *csdev,
unsigned long cfg_id,
int preset);
+void coresight_cfg_disable_dev_config(struct coresight_device *csdev);
#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */
2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
Adds handling for the cs_etm/cs_config directory that contains loaded configurations that may be selected by the perf command line using the @name syntax.
Adds flag to mark the hash ID found as a configuration name rather than a sink name.
Signed-off-by: Mike Leach mike.leach@linaro.org --- include/linux/coresight-pmu.h | 3 +++ tools/include/linux/coresight-pmu.h | 3 +++ tools/perf/arch/arm/util/cs-etm.c | 17 +++++++++++++++-- 3 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/include/linux/coresight-pmu.h b/include/linux/coresight-pmu.h index b0e35eec6499..9bb0fb46f576 100644 --- a/include/linux/coresight-pmu.h +++ b/include/linux/coresight-pmu.h @@ -22,6 +22,9 @@ #define ETM4_CFG_BIT_TS 11 #define ETM4_CFG_BIT_RETSTK 12
+/* Coresight config select bit - mark sink ID as a config ID */ +#define CSSYS_BIT_CONFIG_SEL 36 + static inline int coresight_get_trace_id(int cpu) { /* diff --git a/tools/include/linux/coresight-pmu.h b/tools/include/linux/coresight-pmu.h index b0e35eec6499..9bb0fb46f576 100644 --- a/tools/include/linux/coresight-pmu.h +++ b/tools/include/linux/coresight-pmu.h @@ -22,6 +22,9 @@ #define ETM4_CFG_BIT_TS 11 #define ETM4_CFG_BIT_RETSTK 12
+/* Coresight config select bit - mark sink ID as a config ID */ +#define CSSYS_BIT_CONFIG_SEL 36 + static inline int coresight_get_trace_id(int cpu) { /* diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c index cad7bf783413..4c46448396f1 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c @@ -219,6 +219,7 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu, struct evsel_config_term *term; int ret = -EINVAL; u32 hash; + u64 config_sel = 0;
if (evsel->core.attr.config2 & GENMASK(31, 0)) return 0; @@ -228,9 +229,21 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu, continue;
sink = term->val.str; - snprintf(path, PATH_MAX, "sinks/%s", sink);
+ /* re-using @val for config select - check for config first */ + snprintf(path, PATH_MAX, "cs_config/%s", sink); ret = perf_pmu__scan_file(pmu, path, "%x", &hash); + + if (ret != 1) { + /* not config, look for sink */ + snprintf(path, PATH_MAX, "sinks/%s", sink); + + ret = perf_pmu__scan_file(pmu, path, "%x", &hash); + } else { + /* is a config - mark as such */ + config_sel = BIT(CSSYS_BIT_CONFIG_SEL); + } + if (ret != 1) { pr_err("failed to set sink "%s" on event %s with %d (%s)\n", sink, evsel__name(evsel), errno, @@ -238,7 +251,7 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu, return ret; }
- evsel->core.attr.config2 |= hash; + evsel->core.attr.config2 |= hash | config_sel; return 0; }
Hi Mike
On 08/27/2020 03:34 PM, Mike Leach wrote:
Adds handling for the cs_etm/cs_config directory that contains loaded configurations that may be selected by the perf command line using the @name syntax.
Adds flag to mark the hash ID found as a configuration name rather than a sink name.
Signed-off-by: Mike Leach mike.leach@linaro.org
Do we need this to be controlled by "@" ?
Can we make it work like :
cat /sys/bus/event_source/devices/cs_etm/format/cs_sys_cfg config2:36
cat /sys/bus/event_source/devices/cs_etm/events/autofdo cs_sys_cfg=1,sinkid=<hash-for-autodo>
Cheers Suzuki
include/linux/coresight-pmu.h | 3 +++ tools/include/linux/coresight-pmu.h | 3 +++ tools/perf/arch/arm/util/cs-etm.c | 17 +++++++++++++++-- 3 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/include/linux/coresight-pmu.h b/include/linux/coresight-pmu.h index b0e35eec6499..9bb0fb46f576 100644 --- a/include/linux/coresight-pmu.h +++ b/include/linux/coresight-pmu.h @@ -22,6 +22,9 @@ #define ETM4_CFG_BIT_TS 11 #define ETM4_CFG_BIT_RETSTK 12 +/* Coresight config select bit - mark sink ID as a config ID */ +#define CSSYS_BIT_CONFIG_SEL 36
- static inline int coresight_get_trace_id(int cpu) { /*
diff --git a/tools/include/linux/coresight-pmu.h b/tools/include/linux/coresight-pmu.h index b0e35eec6499..9bb0fb46f576 100644 --- a/tools/include/linux/coresight-pmu.h +++ b/tools/include/linux/coresight-pmu.h @@ -22,6 +22,9 @@ #define ETM4_CFG_BIT_TS 11 #define ETM4_CFG_BIT_RETSTK 12 +/* Coresight config select bit - mark sink ID as a config ID */ +#define CSSYS_BIT_CONFIG_SEL 36
- static inline int coresight_get_trace_id(int cpu) { /*
diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c index cad7bf783413..4c46448396f1 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c @@ -219,6 +219,7 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu, struct evsel_config_term *term; int ret = -EINVAL; u32 hash;
- u64 config_sel = 0;
if (evsel->core.attr.config2 & GENMASK(31, 0)) return 0; @@ -228,9 +229,21 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu, continue; sink = term->val.str;
snprintf(path, PATH_MAX, "sinks/%s", sink);
/* re-using @val for config select - check for config first */
ret = perf_pmu__scan_file(pmu, path, "%x", &hash);snprintf(path, PATH_MAX, "cs_config/%s", sink);
if (ret != 1) {
/* not config, look for sink */
snprintf(path, PATH_MAX, "sinks/%s", sink);
ret = perf_pmu__scan_file(pmu, path, "%x", &hash);
} else {
/* is a config - mark as such */
config_sel = BIT(CSSYS_BIT_CONFIG_SEL);
}
- if (ret != 1) { pr_err("failed to set sink "%s" on event %s with %d (%s)\n", sink, evsel__name(evsel), errno,
@@ -238,7 +251,7 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu, return ret; }
evsel->core.attr.config2 |= hash;
return 0; }evsel->core.attr.config2 |= hash | config_sel;
Hi Suzuki,
On Wed, 7 Oct 2020 at 10:36, Suzuki K Poulose suzuki.poulose@arm.com wrote:
Hi Mike
On 08/27/2020 03:34 PM, Mike Leach wrote:
Adds handling for the cs_etm/cs_config directory that contains loaded configurations that may be selected by the perf command line using the @name syntax.
Adds flag to mark the hash ID found as a configuration name rather than a sink name.
Signed-off-by: Mike Leach mike.leach@linaro.org
Do we need this to be controlled by "@" ?
Can we make it work like :
cat /sys/bus/event_source/devices/cs_etm/format/cs_sys_cfg config2:36
cat /sys/bus/event_source/devices/cs_etm/events/autofdo cs_sys_cfg=1,sinkid=<hash-for-autodo>
Not sure how this works on the command line?
Are you suggesting the replacing the easy to use: perf -e cs_etm/@autofdo/ ... with: perf -e cs_etm/cs_sys_cfg=1,sinkid=<some value i've got to look up and copy>/ ... or are you suggesting that the two syntax variants should be equivalent - as per the @sink / sinkid=<sink_hash> are?
Given that for a given name configuration such as 'autofdo', this will be visible to the user as 'autofdo' in configfs, will be visible to the user in /sys/bus/event_source/devices/cs_etm/cs_config as 'autofdo', requiring the use two elements, one of which is sinkid is overly complex and misleading given this is not a sink selection. One of the drivers for me doing the auto sink selection was to enable the use of configurations - including the selection of such.
Having looked at the perf command processing and yacc etc, it did not seem sensible to try to come up with a new command option given that this was easy to use and designed to convert a string token into a hash value that could be passed to the kernel drivers later.
The use of named configurations and using @ is predicated on making selection simple. There is no reason I can see for not using the @ syntax, but it may be possible to include an equivalence with a flag.sinkid=<hash> syntax, which would also have the advantage of resulting in an entry in the format directory marking bit 36 of config2 used.
Thanks and Regards
Mike
Cheers Suzuki
include/linux/coresight-pmu.h | 3 +++ tools/include/linux/coresight-pmu.h | 3 +++ tools/perf/arch/arm/util/cs-etm.c | 17 +++++++++++++++-- 3 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/include/linux/coresight-pmu.h b/include/linux/coresight-pmu.h index b0e35eec6499..9bb0fb46f576 100644 --- a/include/linux/coresight-pmu.h +++ b/include/linux/coresight-pmu.h @@ -22,6 +22,9 @@ #define ETM4_CFG_BIT_TS 11 #define ETM4_CFG_BIT_RETSTK 12
+/* Coresight config select bit - mark sink ID as a config ID */ +#define CSSYS_BIT_CONFIG_SEL 36
- static inline int coresight_get_trace_id(int cpu) { /*
diff --git a/tools/include/linux/coresight-pmu.h b/tools/include/linux/coresight-pmu.h index b0e35eec6499..9bb0fb46f576 100644 --- a/tools/include/linux/coresight-pmu.h +++ b/tools/include/linux/coresight-pmu.h @@ -22,6 +22,9 @@ #define ETM4_CFG_BIT_TS 11 #define ETM4_CFG_BIT_RETSTK 12
+/* Coresight config select bit - mark sink ID as a config ID */ +#define CSSYS_BIT_CONFIG_SEL 36
- static inline int coresight_get_trace_id(int cpu) { /*
diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c index cad7bf783413..4c46448396f1 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c @@ -219,6 +219,7 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu, struct evsel_config_term *term; int ret = -EINVAL; u32 hash;
u64 config_sel = 0; if (evsel->core.attr.config2 & GENMASK(31, 0)) return 0;
@@ -228,9 +229,21 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu, continue;
sink = term->val.str;
snprintf(path, PATH_MAX, "sinks/%s", sink);
/* re-using @val for config select - check for config first */
snprintf(path, PATH_MAX, "cs_config/%s", sink); ret = perf_pmu__scan_file(pmu, path, "%x", &hash);
if (ret != 1) {
/* not config, look for sink */
snprintf(path, PATH_MAX, "sinks/%s", sink);
ret = perf_pmu__scan_file(pmu, path, "%x", &hash);
} else {
/* is a config - mark as such */
config_sel = BIT(CSSYS_BIT_CONFIG_SEL);
}
if (ret != 1) { pr_err("failed to set sink \"%s\" on event %s with %d (%s)\n", sink, evsel__name(evsel), errno,
@@ -238,7 +251,7 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu, return ret; }
evsel->core.attr.config2 |= hash;
evsel->core.attr.config2 |= hash | config_sel; return 0; }
On 10/07/2020 12:07 PM, Mike Leach wrote:
Hi Suzuki,
On Wed, 7 Oct 2020 at 10:36, Suzuki K Poulose suzuki.poulose@arm.com wrote:
Hi Mike
On 08/27/2020 03:34 PM, Mike Leach wrote:
Adds handling for the cs_etm/cs_config directory that contains loaded configurations that may be selected by the perf command line using the @name syntax.
Adds flag to mark the hash ID found as a configuration name rather than a sink name.
Signed-off-by: Mike Leach mike.leach@linaro.org
Do we need this to be controlled by "@" ?
Can we make it work like :
cat /sys/bus/event_source/devices/cs_etm/format/cs_sys_cfg config2:36
cat /sys/bus/event_source/devices/cs_etm/events/autofdo cs_sys_cfg=1,sinkid=<hash-for-autodo>
Not sure how this works on the command line?
Are you suggesting the replacing the easy to use: perf -e cs_etm/@autofdo/ ... with:
Sorry I was not clear in my comments above
perf -e cs_etm/cs_sys_cfg=1,sinkid=<some value i've got to look up and copy>/ ... or are you suggesting that the two syntax variants should be equivalent - as per the @sink / sinkid=<sink_hash> are?
No. This will become :
perf record -e cs_etm/autofdo/
Perf will be able to expand "autofdo" to "cs_sys_cfg=1,sinkid=<autofdo-hash>" based on the fact that
cat /sys/bus/event_source/devices/cs_etm/events/autofdo cs_sys_cfg=1,sinkid=<hash-for-autodo>
and set the config2 automatically. So that you don't need special handling in perf tool.
Cheers Suzuki
Hi Suzuki,
On Wed, 7 Oct 2020 at 12:13, Suzuki K Poulose suzuki.poulose@arm.com wrote:
On 10/07/2020 12:07 PM, Mike Leach wrote:
Hi Suzuki,
On Wed, 7 Oct 2020 at 10:36, Suzuki K Poulose suzuki.poulose@arm.com wrote:
Hi Mike
On 08/27/2020 03:34 PM, Mike Leach wrote:
Adds handling for the cs_etm/cs_config directory that contains loaded configurations that may be selected by the perf command line using the @name syntax.
Adds flag to mark the hash ID found as a configuration name rather than a sink name.
Signed-off-by: Mike Leach mike.leach@linaro.org
Do we need this to be controlled by "@" ?
Can we make it work like :
cat /sys/bus/event_source/devices/cs_etm/format/cs_sys_cfg config2:36
cat /sys/bus/event_source/devices/cs_etm/events/autofdo cs_sys_cfg=1,sinkid=<hash-for-autodo>
Not sure how this works on the command line?
Are you suggesting the replacing the easy to use: perf -e cs_etm/@autofdo/ ... with:
Sorry I was not clear in my comments above
perf -e cs_etm/cs_sys_cfg=1,sinkid=<some value i've got to look up and copy>/ ... or are you suggesting that the two syntax variants should be equivalent - as per the @sink / sinkid=<sink_hash> are?
No. This will become :
perf record -e cs_etm/autofdo/
Perf will be able to expand "autofdo" to "cs_sys_cfg=1,sinkid=<autofdo-hash>" based on the fact that
cat /sys/bus/event_source/devices/cs_etm/events/autofdo cs_sys_cfg=1,sinkid=<hash-for-autodo>
and set the config2 automatically. So that you don't need special handling in perf tool.
OK - didn't realise it would do that - but it does sound better! Not seeing an events directory in my cs_etm on the DB410 - presumably I have to create that?
Cheers
Mike
Cheers Suzuki
On 10/07/2020 12:21 PM, Mike Leach wrote:
Hi Suzuki,
On Wed, 7 Oct 2020 at 12:13, Suzuki K Poulose suzuki.poulose@arm.com wrote:
On 10/07/2020 12:07 PM, Mike Leach wrote:
Hi Suzuki,
On Wed, 7 Oct 2020 at 10:36, Suzuki K Poulose suzuki.poulose@arm.com wrote:
Hi Mike
On 08/27/2020 03:34 PM, Mike Leach wrote:
Adds handling for the cs_etm/cs_config directory that contains loaded configurations that may be selected by the perf command line using the @name syntax.
Adds flag to mark the hash ID found as a configuration name rather than a sink name.
Signed-off-by: Mike Leach mike.leach@linaro.org
Do we need this to be controlled by "@" ?
Can we make it work like :
cat /sys/bus/event_source/devices/cs_etm/format/cs_sys_cfg config2:36
cat /sys/bus/event_source/devices/cs_etm/events/autofdo cs_sys_cfg=1,sinkid=<hash-for-autodo>
Not sure how this works on the command line?
Are you suggesting the replacing the easy to use: perf -e cs_etm/@autofdo/ ... with:
Sorry I was not clear in my comments above
perf -e cs_etm/cs_sys_cfg=1,sinkid=<some value i've got to look up and copy>/ ... or are you suggesting that the two syntax variants should be equivalent - as per the @sink / sinkid=<sink_hash> are?
No. This will become :
perf record -e cs_etm/autofdo/
Perf will be able to expand "autofdo" to "cs_sys_cfg=1,sinkid=<autofdo-hash>" based on the fact that
cat /sys/bus/event_source/devices/cs_etm/events/autofdo cs_sys_cfg=1,sinkid=<hash-for-autodo>
and set the config2 automatically. So that you don't need special handling in perf tool.
OK - didn't realise it would do that - but it does sound better! Not seeing an events directory in my cs_etm on the DB410 - presumably I have to create that?
Correct, we don't have the event group yet, mainly because our configs were 1bit fields, except for the sinkid. We could add that as well.
e.g,
cat /sys/..event_source/.../cs_etm/events/tmc_etr0 sinkid=<hash-for-tmc_etr0>
Cheers Suzuki
Hi,
On Wed, 7 Oct 2020 at 13:29, Suzuki K Poulose suzuki.poulose@arm.com wrote:
On 10/07/2020 12:21 PM, Mike Leach wrote:
Hi Suzuki,
On Wed, 7 Oct 2020 at 12:13, Suzuki K Poulose suzuki.poulose@arm.com wrote:
On 10/07/2020 12:07 PM, Mike Leach wrote:
Hi Suzuki,
On Wed, 7 Oct 2020 at 10:36, Suzuki K Poulose suzuki.poulose@arm.com wrote:
Hi Mike
On 08/27/2020 03:34 PM, Mike Leach wrote:
Adds handling for the cs_etm/cs_config directory that contains loaded configurations that may be selected by the perf command line using the @name syntax.
Adds flag to mark the hash ID found as a configuration name rather than a sink name.
Signed-off-by: Mike Leach mike.leach@linaro.org
Do we need this to be controlled by "@" ?
Can we make it work like :
cat /sys/bus/event_source/devices/cs_etm/format/cs_sys_cfg config2:36
cat /sys/bus/event_source/devices/cs_etm/events/autofdo cs_sys_cfg=1,sinkid=<hash-for-autodo>
Not sure how this works on the command line?
Are you suggesting the replacing the easy to use: perf -e cs_etm/@autofdo/ ... with:
Sorry I was not clear in my comments above
perf -e cs_etm/cs_sys_cfg=1,sinkid=<some value i've got to look up and copy>/ ... or are you suggesting that the two syntax variants should be equivalent - as per the @sink / sinkid=<sink_hash> are?
No. This will become :
perf record -e cs_etm/autofdo/
Perf will be able to expand "autofdo" to "cs_sys_cfg=1,sinkid=<autofdo-hash>" based on the fact that
cat /sys/bus/event_source/devices/cs_etm/events/autofdo cs_sys_cfg=1,sinkid=<hash-for-autodo>
and set the config2 automatically. So that you don't need special handling in perf tool.
OK - didn't realise it would do that - but it does sound better! Not seeing an events directory in my cs_etm on the DB410 - presumably I have to create that?
Correct, we don't have the event group yet, mainly because our configs were 1bit fields, except for the sinkid. We could add that as well.
e.g,
cat /sys/..event_source/.../cs_etm/events/tmc_etr0 sinkid=<hash-for-tmc_etr0>
Cheers Suzuki
OK - thanks. I'll stick to what is immediately relevant for this set now. As this is a new command option / use case, not using the @ is fine.
Not sure that changing the existing command line we have been using for years for sinks will be equally well received!
Mike
On 10/07/2020 01:39 PM, Mike Leach wrote:
Hi,
On Wed, 7 Oct 2020 at 13:29, Suzuki K Poulose suzuki.poulose@arm.com wrote:
On 10/07/2020 12:21 PM, Mike Leach wrote:
Hi Suzuki,
On Wed, 7 Oct 2020 at 12:13, Suzuki K Poulose suzuki.poulose@arm.com wrote:
On 10/07/2020 12:07 PM, Mike Leach wrote:
Hi Suzuki,
On Wed, 7 Oct 2020 at 10:36, Suzuki K Poulose suzuki.poulose@arm.com wrote:
Hi Mike
On 08/27/2020 03:34 PM, Mike Leach wrote: > Adds handling for the cs_etm/cs_config directory that contains loaded > configurations that may be selected by the perf command line using the > @name syntax. > > Adds flag to mark the hash ID found as a configuration name rather > than a sink name. > > Signed-off-by: Mike Leach mike.leach@linaro.org
Do we need this to be controlled by "@" ?
Can we make it work like :
cat /sys/bus/event_source/devices/cs_etm/format/cs_sys_cfg config2:36
cat /sys/bus/event_source/devices/cs_etm/events/autofdo cs_sys_cfg=1,sinkid=<hash-for-autodo>
Not sure how this works on the command line?
Are you suggesting the replacing the easy to use: perf -e cs_etm/@autofdo/ ... with:
Sorry I was not clear in my comments above
perf -e cs_etm/cs_sys_cfg=1,sinkid=<some value i've got to look up and copy>/ ... or are you suggesting that the two syntax variants should be equivalent - as per the @sink / sinkid=<sink_hash> are?
No. This will become :
perf record -e cs_etm/autofdo/
Perf will be able to expand "autofdo" to "cs_sys_cfg=1,sinkid=<autofdo-hash>" based on the fact that
cat /sys/bus/event_source/devices/cs_etm/events/autofdo cs_sys_cfg=1,sinkid=<hash-for-autodo>
and set the config2 automatically. So that you don't need special handling in perf tool.
OK - didn't realise it would do that - but it does sound better! Not seeing an events directory in my cs_etm on the DB410 - presumably I have to create that?
Correct, we don't have the event group yet, mainly because our configs were 1bit fields, except for the sinkid. We could add that as well.
e.g,
cat /sys/..event_source/.../cs_etm/events/tmc_etr0 sinkid=<hash-for-tmc_etr0>
Cheers Suzuki
OK - thanks. I'll stick to what is immediately relevant for this set now. As this is a new command option / use case, not using the @ is fine.
Sure, np.
Not sure that changing the existing command line we have been using for years for sinks will be equally well received!
Btw, that doesn't mean we have to stop supporting the existing way /@tmc_etr0/. Both are covered by different code in the perf tool.
Cheers Suzuki
On Thu, Aug 27, 2020 at 03:34:08PM +0100, Mike Leach wrote:
Adds handling for the cs_etm/cs_config directory that contains loaded configurations that may be selected by the perf command line using the @name syntax.
Adds flag to mark the hash ID found as a configuration name rather than a sink name.
Signed-off-by: Mike Leach mike.leach@linaro.org
include/linux/coresight-pmu.h | 3 +++ tools/include/linux/coresight-pmu.h | 3 +++ tools/perf/arch/arm/util/cs-etm.c | 17 +++++++++++++++-- 3 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/include/linux/coresight-pmu.h b/include/linux/coresight-pmu.h index b0e35eec6499..9bb0fb46f576 100644 --- a/include/linux/coresight-pmu.h +++ b/include/linux/coresight-pmu.h @@ -22,6 +22,9 @@ #define ETM4_CFG_BIT_TS 11 #define ETM4_CFG_BIT_RETSTK 12 +/* Coresight config select bit - mark sink ID as a config ID */ +#define CSSYS_BIT_CONFIG_SEL 36
static inline int coresight_get_trace_id(int cpu) { /* diff --git a/tools/include/linux/coresight-pmu.h b/tools/include/linux/coresight-pmu.h index b0e35eec6499..9bb0fb46f576 100644 --- a/tools/include/linux/coresight-pmu.h +++ b/tools/include/linux/coresight-pmu.h @@ -22,6 +22,9 @@ #define ETM4_CFG_BIT_TS 11 #define ETM4_CFG_BIT_RETSTK 12 +/* Coresight config select bit - mark sink ID as a config ID */ +#define CSSYS_BIT_CONFIG_SEL 36
I would make this bit 32 and the presets 33-36. That way if we need more presets then we don't have to mess around with anything else. Note that this needs to be communicated to perf using the PMU_FORMAT_ATTR() macro in cs-etm-perf.c, as you did for the presets.
static inline int coresight_get_trace_id(int cpu) { /* diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c index cad7bf783413..4c46448396f1 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c @@ -219,6 +219,7 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu, struct evsel_config_term *term; int ret = -EINVAL; u32 hash;
- u64 config_sel = 0;
if (evsel->core.attr.config2 & GENMASK(31, 0)) return 0; @@ -228,9 +229,21 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu, continue; sink = term->val.str;
s/sink/str
Otherwise the code becomes confusing and harder to maintain.
snprintf(path, PATH_MAX, "sinks/%s", sink);
/* re-using @val for config select - check for config first */
snprintf(path, PATH_MAX, "cs_config/%s", sink);
This is already in the cs_etm directory so it could just be "configs" to follow the "sinks".
ret = perf_pmu__scan_file(pmu, path, "%x", &hash);
if (ret != 1) {
/* not config, look for sink */
snprintf(path, PATH_MAX, "sinks/%s", sink);
ret = perf_pmu__scan_file(pmu, path, "%x", &hash);
} else {
/* is a config - mark as such */
config_sel = BIT(CSSYS_BIT_CONFIG_SEL);
}
- if (ret != 1) { pr_err("failed to set sink "%s" on event %s with %d (%s)\n", sink, evsel__name(evsel), errno,
The error message will need to be changed based on whether we have a configuration or a sink. I would also change the name of the function, as cs_etm_set_sink_attr() isn't accurate anymore. Something like cs_etm_set_session_attr() would be better.
@@ -238,7 +251,7 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu, return ret; }
evsel->core.attr.config2 |= hash;
return 0; }evsel->core.attr.config2 |= hash | config_sel;
2.17.1
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-etm-perf.c | 89 ++++++++++++++----- .../hwtracing/coresight/coresight-etm-perf.h | 6 ++ .../hwtracing/coresight/coresight-syscfg.c | 7 ++ .../hwtracing/coresight/coresight-syscfg.h | 2 + 4 files changed, 83 insertions(+), 21 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 2d619b764738..d2a42a7305fe 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,8 @@ 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, "config2:32-35");
static struct attribute *etm_config_formats_attr[] = { &format_attr_cycacc.attr, @@ -41,6 +45,7 @@ static struct attribute *etm_config_formats_attr[] = { &format_attr_timestamp.attr, &format_attr_retstack.attr, &format_attr_sinkid.attr, + &format_attr_preset.attr, NULL, };
@@ -58,9 +63,20 @@ 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 = "cs_config", + .attrs = etm_config_cscfg_attr, +}; + + static const struct attribute_group *etm_pmu_attr_groups[] = { &etm_pmu_format_group, &etm_pmu_sinks_group, + &etm_pmu_cscfg_group, NULL, };
@@ -529,21 +545,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; @@ -552,7 +564,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));
@@ -566,31 +577,67 @@ 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; }
+int etm_perf_add_symlink_cscfg(struct device *dev, struct cs_cfg_config *cs_cfg) +{ + if (cs_cfg->ea != NULL) + return -EINVAL; + + return etm_perf_add_symlink_group(dev, &cs_cfg->ea, + cs_cfg->desc->name, "cs_config"); +} + +void etm_perf_del_symlink_cscfg(struct cs_cfg_config *cs_cfg) +{ + if (!cs_cfg->ea) + return; + + etm_perf_del_symlink_group(cs_cfg->ea, "cs_config"); + cs_cfg->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..a718d0778bcf 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 cs_cfg_config;
/* * In both ETMv3 and v4 the maximum number of address comparator implentable @@ -69,6 +70,8 @@ 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 cs_cfg_config *cs_cfg); +void etm_perf_del_symlink_cscfg(struct cs_cfg_config *cs_cfg); #else static inline int etm_perf_symlink(struct coresight_device *csdev, bool link) { return -EINVAL; } @@ -79,6 +82,9 @@ static inline void *etm_perf_sink_config(struct perf_output_handle *handle) { return NULL; } +int etm_perf_add_symlink_cscfg(struct device *dev, struct cs_cfg_config *cs_cfg) +{ return -EINVAL; } +void etm_perf_del_symlink_cscfg(struct cs_cfg_config *cs_cfg) {}
#endif /* CONFIG_CORESIGHT */
diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 479dc81993c2..8f6a50fe86dd 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"
@@ -103,6 +104,7 @@ static int cscfg_add_dev_cfg(struct coresight_device *csdev, if (!dev_cfg) return -ENOMEM; dev_cfg->desc = cfg->desc; + dev_cfg->id_hash = (unsigned long)cfg->ea->var; } dev_cfg->feats[dev_cfg->nr_feat++] = feat; } @@ -231,6 +233,11 @@ static int cscfg_load_config(struct cs_cfg_config_desc *cfg_desc) return -ENOMEM; cfg->desc = cfg_desc;
+ /* add config name to perf event directory */ + err = etm_perf_add_symlink_cscfg(to_device_cscfg(), cfg); + if (err) + return err; + /* add config to any matching registered device */ err = cscfg_add_cfg_to_devs(cfg); if (err) diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 8ba800cc2e42..30dc12a7ecaa 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -48,10 +48,12 @@ struct cscfg_featlist_item { * * @desc: Descriptor for the configuration. * @item: List entry. + * @ea: Attribute for perf selection. */ struct cs_cfg_config { const struct cs_cfg_config_desc *desc; struct list_head item; + struct dev_ext_attribute *ea; };
/**
Hi Mike,
On Thu, Aug 27, 2020 at 03:34:09PM +0100, 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-etm-perf.c | 89 ++++++++++++++----- .../hwtracing/coresight/coresight-etm-perf.h | 6 ++ .../hwtracing/coresight/coresight-syscfg.c | 7 ++ .../hwtracing/coresight/coresight-syscfg.h | 2 + 4 files changed, 83 insertions(+), 21 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 2d619b764738..d2a42a7305fe 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,8 @@ 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, "config2:32-35");
More brain gymnastics on this... I think it would make sense to keep bitfields for sink and configuration distinct so that users can specify a sink and a configuration to use at the same time:
PMU_FORMAT_ATTR(preset, "config1:0-3"); PMU_FORMAT_ATTR(sinkid, "config2:0-31"); PMU_FORMAT_ATTR(configid, "config2:32-63");
We (still) have room and it is just a matter of time before someone wants to do that.
More comments to come...
Thanks, Mathieu
static struct attribute *etm_config_formats_attr[] = { &format_attr_cycacc.attr, @@ -41,6 +45,7 @@ static struct attribute *etm_config_formats_attr[] = { &format_attr_timestamp.attr, &format_attr_retstack.attr, &format_attr_sinkid.attr,
- &format_attr_preset.attr, NULL,
}; @@ -58,9 +63,20 @@ 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 = "cs_config",
- .attrs = etm_config_cscfg_attr,
+};
static const struct attribute_group *etm_pmu_attr_groups[] = { &etm_pmu_format_group, &etm_pmu_sinks_group,
- &etm_pmu_cscfg_group, NULL,
}; @@ -529,21 +545,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; @@ -552,7 +564,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));
@@ -566,31 +577,67 @@ 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;
} +int etm_perf_add_symlink_cscfg(struct device *dev, struct cs_cfg_config *cs_cfg) +{
- if (cs_cfg->ea != NULL)
return -EINVAL;
- return etm_perf_add_symlink_group(dev, &cs_cfg->ea,
cs_cfg->desc->name, "cs_config");
+}
+void etm_perf_del_symlink_cscfg(struct cs_cfg_config *cs_cfg) +{
- if (!cs_cfg->ea)
return;
- etm_perf_del_symlink_group(cs_cfg->ea, "cs_config");
- cs_cfg->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..a718d0778bcf 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 cs_cfg_config; /*
- In both ETMv3 and v4 the maximum number of address comparator implentable
@@ -69,6 +70,8 @@ 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 cs_cfg_config *cs_cfg); +void etm_perf_del_symlink_cscfg(struct cs_cfg_config *cs_cfg); #else static inline int etm_perf_symlink(struct coresight_device *csdev, bool link) { return -EINVAL; } @@ -79,6 +82,9 @@ static inline void *etm_perf_sink_config(struct perf_output_handle *handle) { return NULL; } +int etm_perf_add_symlink_cscfg(struct device *dev, struct cs_cfg_config *cs_cfg) +{ return -EINVAL; } +void etm_perf_del_symlink_cscfg(struct cs_cfg_config *cs_cfg) {} #endif /* CONFIG_CORESIGHT */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 479dc81993c2..8f6a50fe86dd 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" @@ -103,6 +104,7 @@ static int cscfg_add_dev_cfg(struct coresight_device *csdev, if (!dev_cfg) return -ENOMEM; dev_cfg->desc = cfg->desc;
}dev_cfg->id_hash = (unsigned long)cfg->ea->var; } dev_cfg->feats[dev_cfg->nr_feat++] = feat;
@@ -231,6 +233,11 @@ static int cscfg_load_config(struct cs_cfg_config_desc *cfg_desc) return -ENOMEM; cfg->desc = cfg_desc;
- /* add config name to perf event directory */
- err = etm_perf_add_symlink_cscfg(to_device_cscfg(), cfg);
- if (err)
return err;
- /* add config to any matching registered device */ err = cscfg_add_cfg_to_devs(cfg); if (err)
diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 8ba800cc2e42..30dc12a7ecaa 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -48,10 +48,12 @@ struct cscfg_featlist_item {
- @desc: Descriptor for the configuration.
- @item: List entry.
*/
- @ea: Attribute for perf selection.
struct cs_cfg_config { const struct cs_cfg_config_desc *desc; struct list_head item;
- struct dev_ext_attribute *ea;
}; /** -- 2.17.1
Hi Mathieu,
On Tue, 13 Oct 2020 at 20:49, Mathieu Poirier mathieu.poirier@linaro.org wrote:
Hi Mike,
On Thu, Aug 27, 2020 at 03:34:09PM +0100, 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-etm-perf.c | 89 ++++++++++++++----- .../hwtracing/coresight/coresight-etm-perf.h | 6 ++ .../hwtracing/coresight/coresight-syscfg.c | 7 ++ .../hwtracing/coresight/coresight-syscfg.h | 2 + 4 files changed, 83 insertions(+), 21 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 2d619b764738..d2a42a7305fe 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,8 @@ 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, "config2:32-35");
More brain gymnastics on this... I think it would make sense to keep bitfields for sink and configuration distinct so that users can specify a sink and a configuration to use at the same time:
PMU_FORMAT_ATTR(preset, "config1:0-3"); PMU_FORMAT_ATTR(sinkid, "config2:0-31"); PMU_FORMAT_ATTR(configid, "config2:32-63");
We (still) have room and it is just a matter of time before someone wants to do that.
More comments to come...
I have gone along with this idea, plus Suzuki's concept of using the built in parsing if autofdo ends up in the cs_etm\events\ sub dir. This means no @autofdo any more, which leaves the door wide open to someone writing cs_etm/@tmc_etf0,autofdo/ So this makes a lot of sense and covers that eventuality.
Thanks for the review.
Mike
Thanks, Mathieu
static struct attribute *etm_config_formats_attr[] = { &format_attr_cycacc.attr, @@ -41,6 +45,7 @@ static struct attribute *etm_config_formats_attr[] = { &format_attr_timestamp.attr, &format_attr_retstack.attr, &format_attr_sinkid.attr,
&format_attr_preset.attr, NULL,
};
@@ -58,9 +63,20 @@ 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 = "cs_config",
.attrs = etm_config_cscfg_attr,
+};
static const struct attribute_group *etm_pmu_attr_groups[] = { &etm_pmu_format_group, &etm_pmu_sinks_group,
&etm_pmu_cscfg_group, NULL,
};
@@ -529,21 +545,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;
@@ -552,7 +564,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));
@@ -566,31 +577,67 @@ 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;
}
+int etm_perf_add_symlink_cscfg(struct device *dev, struct cs_cfg_config *cs_cfg) +{
if (cs_cfg->ea != NULL)
return -EINVAL;
return etm_perf_add_symlink_group(dev, &cs_cfg->ea,
cs_cfg->desc->name, "cs_config");
+}
+void etm_perf_del_symlink_cscfg(struct cs_cfg_config *cs_cfg) +{
if (!cs_cfg->ea)
return;
etm_perf_del_symlink_group(cs_cfg->ea, "cs_config");
cs_cfg->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..a718d0778bcf 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 cs_cfg_config;
/*
- In both ETMv3 and v4 the maximum number of address comparator implentable
@@ -69,6 +70,8 @@ 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 cs_cfg_config *cs_cfg); +void etm_perf_del_symlink_cscfg(struct cs_cfg_config *cs_cfg); #else static inline int etm_perf_symlink(struct coresight_device *csdev, bool link) { return -EINVAL; } @@ -79,6 +82,9 @@ static inline void *etm_perf_sink_config(struct perf_output_handle *handle) { return NULL; } +int etm_perf_add_symlink_cscfg(struct device *dev, struct cs_cfg_config *cs_cfg) +{ return -EINVAL; } +void etm_perf_del_symlink_cscfg(struct cs_cfg_config *cs_cfg) {}
#endif /* CONFIG_CORESIGHT */
diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 479dc81993c2..8f6a50fe86dd 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"
@@ -103,6 +104,7 @@ static int cscfg_add_dev_cfg(struct coresight_device *csdev, if (!dev_cfg) return -ENOMEM; dev_cfg->desc = cfg->desc;
dev_cfg->id_hash = (unsigned long)cfg->ea->var; } dev_cfg->feats[dev_cfg->nr_feat++] = feat; }
@@ -231,6 +233,11 @@ static int cscfg_load_config(struct cs_cfg_config_desc *cfg_desc) return -ENOMEM; cfg->desc = cfg_desc;
/* add config name to perf event directory */
err = etm_perf_add_symlink_cscfg(to_device_cscfg(), cfg);
if (err)
return err;
/* add config to any matching registered device */ err = cscfg_add_cfg_to_devs(cfg); if (err)
diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 8ba800cc2e42..30dc12a7ecaa 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -48,10 +48,12 @@ struct cscfg_featlist_item {
- @desc: Descriptor for the configuration.
- @item: List entry.
*/
- @ea: Attribute for perf selection.
struct cs_cfg_config { const struct cs_cfg_config_desc *desc; struct list_head item;
struct dev_ext_attribute *ea;
};
/**
2.17.1
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 | 226 ++++++++++++++++++ .../hwtracing/coresight/coresight-etm4x-cfg.h | 29 +++ .../coresight/coresight-etm4x-core.c | 30 ++- .../coresight/coresight-etm4x-sysfs.c | 3 + 5 files changed, 288 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 177bc6338312..5723094b2b69 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..c355003d3e05 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c @@ -0,0 +1,226 @@ +// 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 cs_cfg_reg *reg, u32 offset) +{ + int err = 0, idx; + struct etmv4_config *drvcfg = &drvdata->config; + + #define MAPREG(cval, elem) \ + case cval: \ + reg->drv_store = &drvcfg->elem; \ + break; + + #define MAPREGIDX(cval, elem, off_idx) \ + case cval: \ + reg->drv_store = &drvcfg->elem[off_idx]; \ + break; + + if (((offset >= TRCEVENTCTL0R) && (offset <= TRCVIPCSSCTLR)) || + ((offset >= TRCSEQRSTEVR) && (offset <= TRCEXTINSELR)) || + ((offset >= TRCCIDCCTLR0) && (offset <= TRCVMIDCCTLR1))) { + switch (offset) { + /* 32 bit single control and filter registers */ + MAPREG(TRCEVENTCTL0R, eventctrl0); + MAPREG(TRCEVENTCTL1R, eventctrl1); + MAPREG(TRCSTALLCTLR, stall_ctrl); + MAPREG(TRCTSCTLR, ts_ctrl); + MAPREG(TRCSYNCPR, syncfreq); + MAPREG(TRCCCCTLR, ccctlr); + MAPREG(TRCBBCTLR, bb_ctrl); + MAPREG(TRCVICTLR, vinst_ctrl); + MAPREG(TRCVIIECTLR, viiectlr); + MAPREG(TRCVISSCTLR, vissctlr); + MAPREG(TRCVIPCSSCTLR, vipcssctlr); + MAPREG(TRCSEQRSTEVR, seq_rst); + MAPREG(TRCSEQSTR, seq_state); + MAPREG(TRCEXTINSELR, ext_inp); + MAPREG(TRCCIDCCTLR0, ctxid_mask0); + MAPREG(TRCCIDCCTLR1, ctxid_mask1); + MAPREG(TRCVMIDCCTLR0, vmid_mask0); + MAPREG(TRCVMIDCCTLR1, vmid_mask1); + default: + err = -EINVAL; + break; + } + } 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]; + else + err = -EINVAL; + } else if ((offset >= TRCSSCCRn(0)) && (offset <= TRCSSPCICRn(7))) { + /* 32 bit, 8 off indexed register sets */ + idx = (offset & GENMASK(4, 0)) / 4; + switch (offset & GENMASK(11, 5)) { + MAPREGIDX(TRCSSCCRn(0), ss_ctrl, idx); + MAPREGIDX(TRCSSCSRn(0), ss_status, idx); + MAPREGIDX(TRCSSPCICRn(0), ss_pe_cmp, idx); + default: + err = -EINVAL; + break; + } + } else if ((offset >= TRCCIDCVRn(0)) && (offset <= TRCVMIDCVRn(7))) { + /* 64 bit, 8 off indexed register sets */ + idx = (offset & GENMASK(5, 0)) / 8; + switch (offset & GENMASK(11, 6)) { + MAPREGIDX(TRCCIDCVRn(0), ctxid_pid, idx); + MAPREGIDX(TRCVMIDCVRn(0), vmid_val, idx); + default: + err = -EINVAL; + break; + } + } 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]; + else + err = -EINVAL; + } 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; + switch (offset & GENMASK(11, 7)) { + MAPREGIDX(TRCACVRn(0), addr_val, idx); + MAPREGIDX(TRCACATRn(0), addr_acc, idx); + default: + err = -EINVAL; + break; + } + + } 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; + switch (offset & GENMASK(11, 4)) { + MAPREGIDX(TRCCNTRLDVRn(0), cntrldvr, idx); + MAPREGIDX(TRCCNTCTLRn(0), cntr_ctrl, idx); + MAPREGIDX(TRCCNTVRn(0), cntr_val, idx); + default: + err = -EINVAL; + break; + } + } else { + err = -EINVAL; + } + + return err; +} + +/** + * etm4_cfg_load_feature - load a feature into a device instance. + * + * @csdev: An ETMv4 CoreSight device. + * @feat_desc: The static feature descriptor to be loaded. + * + * The function will load a feature instance into the device, based on the + * supplied descriptor. The descriptor will be checked to ensure a valid + * feature can be loaded for this ETMv4 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. + */ +static int etm4_cfg_load_feature(struct coresight_device *csdev, + const struct cs_cfg_feature_desc *feat_desc) +{ + struct device *dev = csdev->dev.parent; + struct etmv4_drvdata *drvdata = dev_get_drvdata(dev); + struct cs_cfg_feature *feat; + u32 offset; + int i = 0, err = 0; + + feat = devm_kzalloc(dev, sizeof(struct cs_cfg_feature), GFP_KERNEL); + if (!feat) + return -ENOMEM; + + feat->desc = feat_desc; + feat->dev_spinlock = &drvdata->spinlock; + feat->csdev = csdev; + + /* count the params regs and allocate space. */ + while (feat_desc->params[i++].name) + feat->nr_params++; + + i = 0; + while (feat_desc->regs[i++].flags) + feat->nr_regs++; + + feat->params = devm_kcalloc(dev, feat->nr_params, + sizeof(struct cs_cfg_parameter), + GFP_KERNEL); + if (!feat->params) + return -ENOMEM; + + feat->regs = devm_kcalloc(dev, feat->nr_regs, + sizeof(struct cs_cfg_reg), GFP_KERNEL); + if (!feat->regs) + return -ENOMEM; + + /* load the parameters default values */ + for (i = 0; i < feat->nr_params; i++) + feat->params[i].feat = feat; + + /* process the register descriptions */ + for (i = 0; i < feat->nr_regs; i++) { + offset = feat_desc->regs[i].flags & CS_CFG_REG_ID_MASK; + err = etm4_cfg_map_reg_offset(drvdata, &feat->regs[i], offset); + if (err) + return err; + } + + /* set sysfs representation of the feature */ + err = coresight_cfg_sysfs_add_grp(feat); + + /* add the feature to the device list and init default values */ + if (!err) { + coresight_cfg_list_add_feat(feat); + coresight_cfg_set_def_ops(feat); + feat->ops.reset(feat); + } + 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 cs_cfg_match_info cfg_info; + struct cs_cfg_dev_feat_ops ops; + + cfg_info.dev_name = dev_name; + cfg_info.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 56aed38cd0fa..3a58f835eb63 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); @@ -320,12 +322,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; @@ -383,6 +388,13 @@ static int etm4_parse_event_config(struct etmv4_drvdata *drvdata, /* bit[12], Return stack enable bit */ config->cfg |= BIT(12);
+ /* set any selected configuration */ + if (attr->config2 & BIT(CSSYS_BIT_CONFIG_SEL)) { + cfg_id = (u32)attr->config2; + preset = (attr->config2 >> 32) & 0xF; + ret = coresight_cfg_enable_dev_config(csdev, cfg_id, preset); + } + out: return ret; } @@ -399,7 +411,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 */ @@ -415,6 +427,8 @@ static int etm4_enable_sysfs(struct coresight_device *csdev) struct etm4_enable_arg arg = { }; int ret;
+ coresight_cfg_set_enabled_feats(csdev); + spin_lock(&drvdata->spinlock);
/* @@ -529,11 +543,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 & BIT(CSSYS_BIT_CONFIG_SEL)) + coresight_cfg_disable_dev_config(csdev);
/* * Check if the start/stop logic was active when the unit was stopped. @@ -568,6 +585,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); + coresight_cfg_save_enabled_feats(csdev); cpus_read_unlock();
dev_dbg(&csdev->dev, "ETM tracing disabled\n"); @@ -1519,6 +1537,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); @@ -1571,6 +1596,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 b673e738bc9a..ec182544a064 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);
+ coresight_cfg_reset_feats(to_coresight_device(dev)); + return size; } static DEVICE_ATTR_WO(reset);
Good day,
More comments to come today. I have jumped to this patch in order to have a better picture of the ops->load_feat() called from cscfg_add_feat_csdev(). As such I will concentrate on very specific aspects and will come back to with for a full review. Please see below...
On Thu, Aug 27, 2020 at 03:34:10PM +0100, 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 | 226 ++++++++++++++++++ .../hwtracing/coresight/coresight-etm4x-cfg.h | 29 +++ .../coresight/coresight-etm4x-core.c | 30 ++- .../coresight/coresight-etm4x-sysfs.c | 3 + 5 files changed, 288 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 177bc6338312..5723094b2b69 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..c355003d3e05 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c @@ -0,0 +1,226 @@ +// 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 cs_cfg_reg *reg, u32 offset)
+{
- int err = 0, idx;
- struct etmv4_config *drvcfg = &drvdata->config;
- #define MAPREG(cval, elem) \
case cval: \
reg->drv_store = &drvcfg->elem; \
break;
- #define MAPREGIDX(cval, elem, off_idx) \
case cval: \
reg->drv_store = &drvcfg->elem[off_idx]; \
break;
- if (((offset >= TRCEVENTCTL0R) && (offset <= TRCVIPCSSCTLR)) ||
((offset >= TRCSEQRSTEVR) && (offset <= TRCEXTINSELR)) ||
((offset >= TRCCIDCCTLR0) && (offset <= TRCVMIDCCTLR1))) {
switch (offset) {
/* 32 bit single control and filter registers */
MAPREG(TRCEVENTCTL0R, eventctrl0);
MAPREG(TRCEVENTCTL1R, eventctrl1);
MAPREG(TRCSTALLCTLR, stall_ctrl);
MAPREG(TRCTSCTLR, ts_ctrl);
MAPREG(TRCSYNCPR, syncfreq);
MAPREG(TRCCCCTLR, ccctlr);
MAPREG(TRCBBCTLR, bb_ctrl);
MAPREG(TRCVICTLR, vinst_ctrl);
MAPREG(TRCVIIECTLR, viiectlr);
MAPREG(TRCVISSCTLR, vissctlr);
MAPREG(TRCVIPCSSCTLR, vipcssctlr);
MAPREG(TRCSEQRSTEVR, seq_rst);
MAPREG(TRCSEQSTR, seq_state);
MAPREG(TRCEXTINSELR, ext_inp);
MAPREG(TRCCIDCCTLR0, ctxid_mask0);
MAPREG(TRCCIDCCTLR1, ctxid_mask1);
MAPREG(TRCVMIDCCTLR0, vmid_mask0);
MAPREG(TRCVMIDCCTLR1, vmid_mask1);
default:
err = -EINVAL;
break;
}
- } 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];
else
err = -EINVAL;
- } else if ((offset >= TRCSSCCRn(0)) && (offset <= TRCSSPCICRn(7))) {
/* 32 bit, 8 off indexed register sets */
idx = (offset & GENMASK(4, 0)) / 4;
switch (offset & GENMASK(11, 5)) {
MAPREGIDX(TRCSSCCRn(0), ss_ctrl, idx);
MAPREGIDX(TRCSSCSRn(0), ss_status, idx);
MAPREGIDX(TRCSSPCICRn(0), ss_pe_cmp, idx);
default:
err = -EINVAL;
break;
}
- } else if ((offset >= TRCCIDCVRn(0)) && (offset <= TRCVMIDCVRn(7))) {
/* 64 bit, 8 off indexed register sets */
idx = (offset & GENMASK(5, 0)) / 8;
switch (offset & GENMASK(11, 6)) {
MAPREGIDX(TRCCIDCVRn(0), ctxid_pid, idx);
MAPREGIDX(TRCVMIDCVRn(0), vmid_val, idx);
default:
err = -EINVAL;
break;
}
- } 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];
else
err = -EINVAL;
- } 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;
switch (offset & GENMASK(11, 7)) {
MAPREGIDX(TRCACVRn(0), addr_val, idx);
MAPREGIDX(TRCACATRn(0), addr_acc, idx);
default:
err = -EINVAL;
break;
}
- } 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;
switch (offset & GENMASK(11, 4)) {
MAPREGIDX(TRCCNTRLDVRn(0), cntrldvr, idx);
MAPREGIDX(TRCCNTCTLRn(0), cntr_ctrl, idx);
MAPREGIDX(TRCCNTVRn(0), cntr_val, idx);
default:
err = -EINVAL;
break;
}
- } else {
err = -EINVAL;
- }
- return err;
+}
+/**
- etm4_cfg_load_feature - load a feature into a device instance.
- @csdev: An ETMv4 CoreSight device.
- @feat_desc: The static feature descriptor to be loaded.
- The function will load a feature instance into the device, based on the
- supplied descriptor. The descriptor will be checked to ensure a valid
- feature can be loaded for this ETMv4 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.
- */
+static int etm4_cfg_load_feature(struct coresight_device *csdev,
const struct cs_cfg_feature_desc *feat_desc)
+{
- struct device *dev = csdev->dev.parent;
- struct etmv4_drvdata *drvdata = dev_get_drvdata(dev);
- struct cs_cfg_feature *feat;
- u32 offset;
- int i = 0, err = 0;
- feat = devm_kzalloc(dev, sizeof(struct cs_cfg_feature), GFP_KERNEL);
- if (!feat)
return -ENOMEM;
- feat->desc = feat_desc;
- feat->dev_spinlock = &drvdata->spinlock;
- feat->csdev = csdev;
- /* count the params regs and allocate space. */
- while (feat_desc->params[i++].name)
feat->nr_params++;
- i = 0;
- while (feat_desc->regs[i++].flags)
feat->nr_regs++;
Please add feat_desc->nr_params and feat_desc->nr_regs and use ARRAY_SIZE() instread of counting, the same way we did in the CTI driver.
- feat->params = devm_kcalloc(dev, feat->nr_params,
sizeof(struct cs_cfg_parameter),
GFP_KERNEL);
- if (!feat->params)
return -ENOMEM;
- feat->regs = devm_kcalloc(dev, feat->nr_regs,
sizeof(struct cs_cfg_reg), GFP_KERNEL);
- if (!feat->regs)
return -ENOMEM;
- /* load the parameters default values */
- for (i = 0; i < feat->nr_params; i++)
feat->params[i].feat = feat;
- /* process the register descriptions */
- for (i = 0; i < feat->nr_regs; i++) {
offset = feat_desc->regs[i].flags & CS_CFG_REG_ID_MASK;
err = etm4_cfg_map_reg_offset(drvdata, &feat->regs[i], offset);
if (err)
return err;
- }
- /* set sysfs representation of the feature */
- err = coresight_cfg_sysfs_add_grp(feat);
- /* add the feature to the device list and init default values */
- if (!err) {
coresight_cfg_list_add_feat(feat);
coresight_cfg_set_def_ops(feat);
feat->ops.reset(feat);
- }
Aside from the processing related to the register description, everything in this function could go in cscfg_add_feat_csdev():
list_for_each_entry(curr_item, &cscfg_dev->feat_list, item) { if (curr_item->desc->match_flags & info->flags) { feature = cscfg_alloc_feature(); ... err = ops->load_feat(csdev, curr_item->desc, feature); ... cs_cfg_reset_feat(feature); err = coresight_cfg_sysfs_add_grp(feat); ... coresight_cfg_list_add_feat(csdev, feat); } }
That would be a lot easier to follow and individual drivers wouldn't have to do the setup operations.
I would also do the feature->ops initialisation as part of cscfg_alloc_feature().
I will come back to this patch later.
Thanks, Mathieu
- 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 cs_cfg_match_info cfg_info;
- struct cs_cfg_dev_feat_ops ops;
- cfg_info.dev_name = dev_name;
- cfg_info.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 56aed38cd0fa..3a58f835eb63 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); @@ -320,12 +322,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; @@ -383,6 +388,13 @@ static int etm4_parse_event_config(struct etmv4_drvdata *drvdata, /* bit[12], Return stack enable bit */ config->cfg |= BIT(12);
- /* set any selected configuration */
- if (attr->config2 & BIT(CSSYS_BIT_CONFIG_SEL)) {
cfg_id = (u32)attr->config2;
preset = (attr->config2 >> 32) & 0xF;
ret = coresight_cfg_enable_dev_config(csdev, cfg_id, preset);
- }
out: return ret; } @@ -399,7 +411,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 */
@@ -415,6 +427,8 @@ static int etm4_enable_sysfs(struct coresight_device *csdev) struct etm4_enable_arg arg = { }; int ret;
- coresight_cfg_set_enabled_feats(csdev);
- spin_lock(&drvdata->spinlock);
/* @@ -529,11 +543,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 & BIT(CSSYS_BIT_CONFIG_SEL))
coresight_cfg_disable_dev_config(csdev);
/* * Check if the start/stop logic was active when the unit was stopped. @@ -568,6 +585,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);
- coresight_cfg_save_enabled_feats(csdev); cpus_read_unlock();
dev_dbg(&csdev->dev, "ETM tracing disabled\n"); @@ -1519,6 +1537,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); @@ -1571,6 +1596,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 b673e738bc9a..ec182544a064 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);
- coresight_cfg_reset_feats(to_coresight_device(dev));
- return size;
} static DEVICE_ATTR_WO(reset); -- 2.17.1
On Thu, Aug 27, 2020 at 03:34:10PM +0100, 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 | 226 ++++++++++++++++++ .../hwtracing/coresight/coresight-etm4x-cfg.h | 29 +++ .../coresight/coresight-etm4x-core.c | 30 ++- .../coresight/coresight-etm4x-sysfs.c | 3 + 5 files changed, 288 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 177bc6338312..5723094b2b69 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..c355003d3e05 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c @@ -0,0 +1,226 @@ +// 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 cs_cfg_reg *reg, u32 offset)
+{
- int err = 0, idx;
- struct etmv4_config *drvcfg = &drvdata->config;
- #define MAPREG(cval, elem) \
case cval: \
reg->drv_store = &drvcfg->elem; \
break;
- #define MAPREGIDX(cval, elem, off_idx) \
case cval: \
reg->drv_store = &drvcfg->elem[off_idx]; \
break;
- if (((offset >= TRCEVENTCTL0R) && (offset <= TRCVIPCSSCTLR)) ||
((offset >= TRCSEQRSTEVR) && (offset <= TRCEXTINSELR)) ||
((offset >= TRCCIDCCTLR0) && (offset <= TRCVMIDCCTLR1))) {
switch (offset) {
/* 32 bit single control and filter registers */
MAPREG(TRCEVENTCTL0R, eventctrl0);
MAPREG(TRCEVENTCTL1R, eventctrl1);
MAPREG(TRCSTALLCTLR, stall_ctrl);
MAPREG(TRCTSCTLR, ts_ctrl);
MAPREG(TRCSYNCPR, syncfreq);
MAPREG(TRCCCCTLR, ccctlr);
MAPREG(TRCBBCTLR, bb_ctrl);
MAPREG(TRCVICTLR, vinst_ctrl);
MAPREG(TRCVIIECTLR, viiectlr);
MAPREG(TRCVISSCTLR, vissctlr);
MAPREG(TRCVIPCSSCTLR, vipcssctlr);
MAPREG(TRCSEQRSTEVR, seq_rst);
MAPREG(TRCSEQSTR, seq_state);
MAPREG(TRCEXTINSELR, ext_inp);
MAPREG(TRCCIDCCTLR0, ctxid_mask0);
MAPREG(TRCCIDCCTLR1, ctxid_mask1);
MAPREG(TRCVMIDCCTLR0, vmid_mask0);
MAPREG(TRCVMIDCCTLR1, vmid_mask1);
default:
err = -EINVAL;
break;
}
- } 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];
else
err = -EINVAL;
- } else if ((offset >= TRCSSCCRn(0)) && (offset <= TRCSSPCICRn(7))) {
/* 32 bit, 8 off indexed register sets */
idx = (offset & GENMASK(4, 0)) / 4;
switch (offset & GENMASK(11, 5)) {
MAPREGIDX(TRCSSCCRn(0), ss_ctrl, idx);
MAPREGIDX(TRCSSCSRn(0), ss_status, idx);
MAPREGIDX(TRCSSPCICRn(0), ss_pe_cmp, idx);
default:
err = -EINVAL;
break;
}
- } else if ((offset >= TRCCIDCVRn(0)) && (offset <= TRCVMIDCVRn(7))) {
/* 64 bit, 8 off indexed register sets */
idx = (offset & GENMASK(5, 0)) / 8;
switch (offset & GENMASK(11, 6)) {
MAPREGIDX(TRCCIDCVRn(0), ctxid_pid, idx);
MAPREGIDX(TRCVMIDCVRn(0), vmid_val, idx);
default:
err = -EINVAL;
break;
}
- } 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];
else
err = -EINVAL;
- } 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;
switch (offset & GENMASK(11, 7)) {
MAPREGIDX(TRCACVRn(0), addr_val, idx);
MAPREGIDX(TRCACATRn(0), addr_acc, idx);
default:
err = -EINVAL;
break;
}
- } 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;
switch (offset & GENMASK(11, 4)) {
MAPREGIDX(TRCCNTRLDVRn(0), cntrldvr, idx);
MAPREGIDX(TRCCNTCTLRn(0), cntr_ctrl, idx);
MAPREGIDX(TRCCNTVRn(0), cntr_val, idx);
default:
err = -EINVAL;
break;
}
- } else {
err = -EINVAL;
- }
- return err;
+}
+/**
- etm4_cfg_load_feature - load a feature into a device instance.
- @csdev: An ETMv4 CoreSight device.
- @feat_desc: The static feature descriptor to be loaded.
- The function will load a feature instance into the device, based on the
- supplied descriptor. The descriptor will be checked to ensure a valid
- feature can be loaded for this ETMv4 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.
- */
+static int etm4_cfg_load_feature(struct coresight_device *csdev,
const struct cs_cfg_feature_desc *feat_desc)
+{
- struct device *dev = csdev->dev.parent;
- struct etmv4_drvdata *drvdata = dev_get_drvdata(dev);
- struct cs_cfg_feature *feat;
- u32 offset;
- int i = 0, err = 0;
- feat = devm_kzalloc(dev, sizeof(struct cs_cfg_feature), GFP_KERNEL);
- if (!feat)
return -ENOMEM;
- feat->desc = feat_desc;
- feat->dev_spinlock = &drvdata->spinlock;
- feat->csdev = csdev;
- /* count the params regs and allocate space. */
- while (feat_desc->params[i++].name)
feat->nr_params++;
- i = 0;
- while (feat_desc->regs[i++].flags)
feat->nr_regs++;
- feat->params = devm_kcalloc(dev, feat->nr_params,
sizeof(struct cs_cfg_parameter),
GFP_KERNEL);
- if (!feat->params)
return -ENOMEM;
- feat->regs = devm_kcalloc(dev, feat->nr_regs,
sizeof(struct cs_cfg_reg), GFP_KERNEL);
- if (!feat->regs)
return -ENOMEM;
- /* load the parameters default values */
- for (i = 0; i < feat->nr_params; i++)
feat->params[i].feat = feat;
- /* process the register descriptions */
- for (i = 0; i < feat->nr_regs; i++) {
offset = feat_desc->regs[i].flags & CS_CFG_REG_ID_MASK;
err = etm4_cfg_map_reg_offset(drvdata, &feat->regs[i], offset);
if (err)
return err;
- }
- /* set sysfs representation of the feature */
- err = coresight_cfg_sysfs_add_grp(feat);
- /* add the feature to the device list and init default values */
- if (!err) {
coresight_cfg_list_add_feat(feat);
coresight_cfg_set_def_ops(feat);
feat->ops.reset(feat);
- }
- 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 cs_cfg_match_info cfg_info;
- struct cs_cfg_dev_feat_ops ops;
- cfg_info.dev_name = dev_name;
- cfg_info.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 56aed38cd0fa..3a58f835eb63 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); @@ -320,12 +322,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; @@ -383,6 +388,13 @@ static int etm4_parse_event_config(struct etmv4_drvdata *drvdata, /* bit[12], Return stack enable bit */ config->cfg |= BIT(12);
- /* set any selected configuration */
- if (attr->config2 & BIT(CSSYS_BIT_CONFIG_SEL)) {
cfg_id = (u32)attr->config2;
preset = (attr->config2 >> 32) & 0xF;
If we follow my previous suggestion then the above would look like:
preset = (u32)attr->config1 & 0xF; cfg_id = attr->config2 >> 32;
Just shifting by 32 is obvious when you have this set in mind but insanely difficult to understand for someone trying to figure out what we did. You can use a hard coded value but add a comment that clearly describe what is happening and also reference the PMU_FORMAT_ATTR(configid) at the top of the file.
ret = coresight_cfg_enable_dev_config(csdev, cfg_id, preset);
- }
out: return ret; } @@ -399,7 +411,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 */
@@ -415,6 +427,8 @@ static int etm4_enable_sysfs(struct coresight_device *csdev) struct etm4_enable_arg arg = { }; int ret;
- coresight_cfg_set_enabled_feats(csdev);
Above in etm4_parse_event_config() function coresight_cfg_enable_dev_config() is used, which implies that when using the perf interface configurations are used. But here coresight_cfg_set_enabled_feats() is called and as such from sysfs features are used.
I think it would be best to use configurations for both perf and sysfs to avoid confusion.
Thanks, Mathieu
spin_lock(&drvdata->spinlock); /* @@ -529,11 +543,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 & BIT(CSSYS_BIT_CONFIG_SEL))
coresight_cfg_disable_dev_config(csdev);
/* * Check if the start/stop logic was active when the unit was stopped. @@ -568,6 +585,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);
- coresight_cfg_save_enabled_feats(csdev); cpus_read_unlock();
dev_dbg(&csdev->dev, "ETM tracing disabled\n"); @@ -1519,6 +1537,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); @@ -1571,6 +1596,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 b673e738bc9a..ec182544a064 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);
- coresight_cfg_reset_feats(to_coresight_device(dev));
- return size;
} static DEVICE_ATTR_WO(reset); -- 2.17.1
Hi Mathieu,
On Tue, 13 Oct 2020 at 21:35, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Thu, Aug 27, 2020 at 03:34:10PM +0100, 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 | 226 ++++++++++++++++++ .../hwtracing/coresight/coresight-etm4x-cfg.h | 29 +++ .../coresight/coresight-etm4x-core.c | 30 ++- .../coresight/coresight-etm4x-sysfs.c | 3 + 5 files changed, 288 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 177bc6338312..5723094b2b69 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..c355003d3e05 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c @@ -0,0 +1,226 @@ +// 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 cs_cfg_reg *reg, u32 offset)
+{
int err = 0, idx;
struct etmv4_config *drvcfg = &drvdata->config;
#define MAPREG(cval, elem) \
case cval: \
reg->drv_store = &drvcfg->elem; \
break;
#define MAPREGIDX(cval, elem, off_idx) \
case cval: \
reg->drv_store = &drvcfg->elem[off_idx]; \
break;
if (((offset >= TRCEVENTCTL0R) && (offset <= TRCVIPCSSCTLR)) ||
((offset >= TRCSEQRSTEVR) && (offset <= TRCEXTINSELR)) ||
((offset >= TRCCIDCCTLR0) && (offset <= TRCVMIDCCTLR1))) {
switch (offset) {
/* 32 bit single control and filter registers */
MAPREG(TRCEVENTCTL0R, eventctrl0);
MAPREG(TRCEVENTCTL1R, eventctrl1);
MAPREG(TRCSTALLCTLR, stall_ctrl);
MAPREG(TRCTSCTLR, ts_ctrl);
MAPREG(TRCSYNCPR, syncfreq);
MAPREG(TRCCCCTLR, ccctlr);
MAPREG(TRCBBCTLR, bb_ctrl);
MAPREG(TRCVICTLR, vinst_ctrl);
MAPREG(TRCVIIECTLR, viiectlr);
MAPREG(TRCVISSCTLR, vissctlr);
MAPREG(TRCVIPCSSCTLR, vipcssctlr);
MAPREG(TRCSEQRSTEVR, seq_rst);
MAPREG(TRCSEQSTR, seq_state);
MAPREG(TRCEXTINSELR, ext_inp);
MAPREG(TRCCIDCCTLR0, ctxid_mask0);
MAPREG(TRCCIDCCTLR1, ctxid_mask1);
MAPREG(TRCVMIDCCTLR0, vmid_mask0);
MAPREG(TRCVMIDCCTLR1, vmid_mask1);
default:
err = -EINVAL;
break;
}
} 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];
else
err = -EINVAL;
} else if ((offset >= TRCSSCCRn(0)) && (offset <= TRCSSPCICRn(7))) {
/* 32 bit, 8 off indexed register sets */
idx = (offset & GENMASK(4, 0)) / 4;
switch (offset & GENMASK(11, 5)) {
MAPREGIDX(TRCSSCCRn(0), ss_ctrl, idx);
MAPREGIDX(TRCSSCSRn(0), ss_status, idx);
MAPREGIDX(TRCSSPCICRn(0), ss_pe_cmp, idx);
default:
err = -EINVAL;
break;
}
} else if ((offset >= TRCCIDCVRn(0)) && (offset <= TRCVMIDCVRn(7))) {
/* 64 bit, 8 off indexed register sets */
idx = (offset & GENMASK(5, 0)) / 8;
switch (offset & GENMASK(11, 6)) {
MAPREGIDX(TRCCIDCVRn(0), ctxid_pid, idx);
MAPREGIDX(TRCVMIDCVRn(0), vmid_val, idx);
default:
err = -EINVAL;
break;
}
} 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];
else
err = -EINVAL;
} 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;
switch (offset & GENMASK(11, 7)) {
MAPREGIDX(TRCACVRn(0), addr_val, idx);
MAPREGIDX(TRCACATRn(0), addr_acc, idx);
default:
err = -EINVAL;
break;
}
} 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;
switch (offset & GENMASK(11, 4)) {
MAPREGIDX(TRCCNTRLDVRn(0), cntrldvr, idx);
MAPREGIDX(TRCCNTCTLRn(0), cntr_ctrl, idx);
MAPREGIDX(TRCCNTVRn(0), cntr_val, idx);
default:
err = -EINVAL;
break;
}
} else {
err = -EINVAL;
}
return err;
+}
+/**
- etm4_cfg_load_feature - load a feature into a device instance.
- @csdev: An ETMv4 CoreSight device.
- @feat_desc: The static feature descriptor to be loaded.
- The function will load a feature instance into the device, based on the
- supplied descriptor. The descriptor will be checked to ensure a valid
- feature can be loaded for this ETMv4 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.
- */
+static int etm4_cfg_load_feature(struct coresight_device *csdev,
const struct cs_cfg_feature_desc *feat_desc)
+{
struct device *dev = csdev->dev.parent;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev);
struct cs_cfg_feature *feat;
u32 offset;
int i = 0, err = 0;
feat = devm_kzalloc(dev, sizeof(struct cs_cfg_feature), GFP_KERNEL);
if (!feat)
return -ENOMEM;
feat->desc = feat_desc;
feat->dev_spinlock = &drvdata->spinlock;
feat->csdev = csdev;
/* count the params regs and allocate space. */
while (feat_desc->params[i++].name)
feat->nr_params++;
i = 0;
while (feat_desc->regs[i++].flags)
feat->nr_regs++;
feat->params = devm_kcalloc(dev, feat->nr_params,
sizeof(struct cs_cfg_parameter),
GFP_KERNEL);
if (!feat->params)
return -ENOMEM;
feat->regs = devm_kcalloc(dev, feat->nr_regs,
sizeof(struct cs_cfg_reg), GFP_KERNEL);
if (!feat->regs)
return -ENOMEM;
/* load the parameters default values */
for (i = 0; i < feat->nr_params; i++)
feat->params[i].feat = feat;
/* process the register descriptions */
for (i = 0; i < feat->nr_regs; i++) {
offset = feat_desc->regs[i].flags & CS_CFG_REG_ID_MASK;
err = etm4_cfg_map_reg_offset(drvdata, &feat->regs[i], offset);
if (err)
return err;
}
/* set sysfs representation of the feature */
err = coresight_cfg_sysfs_add_grp(feat);
/* add the feature to the device list and init default values */
if (!err) {
coresight_cfg_list_add_feat(feat);
coresight_cfg_set_def_ops(feat);
feat->ops.reset(feat);
}
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 cs_cfg_match_info cfg_info;
struct cs_cfg_dev_feat_ops ops;
cfg_info.dev_name = dev_name;
cfg_info.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 56aed38cd0fa..3a58f835eb63 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); @@ -320,12 +322,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;
@@ -383,6 +388,13 @@ static int etm4_parse_event_config(struct etmv4_drvdata *drvdata, /* bit[12], Return stack enable bit */ config->cfg |= BIT(12);
/* set any selected configuration */
if (attr->config2 & BIT(CSSYS_BIT_CONFIG_SEL)) {
cfg_id = (u32)attr->config2;
preset = (attr->config2 >> 32) & 0xF;
If we follow my previous suggestion then the above would look like:
preset = (u32)attr->config1 & 0xF; cfg_id = attr->config2 >> 32;
Just shifting by 32 is obvious when you have this set in mind but insanely difficult to understand for someone trying to figure out what we did. You can use a hard coded value but add a comment that clearly describe what is happening and also reference the PMU_FORMAT_ATTR(configid) at the top of the file.
OK will comment / adjust accordingly & have followed your previous idea..
ret = coresight_cfg_enable_dev_config(csdev, cfg_id, preset);
}
out: return ret; } @@ -399,7 +411,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 */
@@ -415,6 +427,8 @@ static int etm4_enable_sysfs(struct coresight_device *csdev) struct etm4_enable_arg arg = { }; int ret;
coresight_cfg_set_enabled_feats(csdev);
Above in etm4_parse_event_config() function coresight_cfg_enable_dev_config() is used, which implies that when using the perf interface configurations are used. But here coresight_cfg_set_enabled_feats() is called and as such from sysfs features are used.
I think it would be best to use configurations for both perf and sysfs to avoid confusion.
The key difference here is that perf can only ever select a configuration. Because sysfs./ configfs is more flexible it is possible for sysfs to activate a feature on an individual device outside of the concept of a system configuration. The thought here being that a feature can be used, perhaps alongside some other specific programming in sysfs to find a combination that works for a given task. This allows a user to try out things which may end up being used later as a proper configuration.
Thanks
Mike
Thanks, Mathieu
spin_lock(&drvdata->spinlock); /*
@@ -529,11 +543,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 & BIT(CSSYS_BIT_CONFIG_SEL))
coresight_cfg_disable_dev_config(csdev); /* * Check if the start/stop logic was active when the unit was stopped.
@@ -568,6 +585,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);
coresight_cfg_save_enabled_feats(csdev); cpus_read_unlock(); dev_dbg(&csdev->dev, "ETM tracing disabled\n");
@@ -1519,6 +1537,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);
@@ -1571,6 +1596,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 b673e738bc9a..ec182544a064 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);
coresight_cfg_reset_feats(to_coresight_device(dev));
return size;
} static DEVICE_ATTR_WO(reset); -- 2.17.1
On Thu, Oct 29, 2020 at 06:42:32PM +0000, Mike Leach wrote:
Hi Mathieu,
On Tue, 13 Oct 2020 at 21:35, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Thu, Aug 27, 2020 at 03:34:10PM +0100, 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 | 226 ++++++++++++++++++ .../hwtracing/coresight/coresight-etm4x-cfg.h | 29 +++ .../coresight/coresight-etm4x-core.c | 30 ++- .../coresight/coresight-etm4x-sysfs.c | 3 + 5 files changed, 288 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 177bc6338312..5723094b2b69 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..c355003d3e05 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c @@ -0,0 +1,226 @@ +// 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 cs_cfg_reg *reg, u32 offset)
+{
int err = 0, idx;
struct etmv4_config *drvcfg = &drvdata->config;
#define MAPREG(cval, elem) \
case cval: \
reg->drv_store = &drvcfg->elem; \
break;
#define MAPREGIDX(cval, elem, off_idx) \
case cval: \
reg->drv_store = &drvcfg->elem[off_idx]; \
break;
if (((offset >= TRCEVENTCTL0R) && (offset <= TRCVIPCSSCTLR)) ||
((offset >= TRCSEQRSTEVR) && (offset <= TRCEXTINSELR)) ||
((offset >= TRCCIDCCTLR0) && (offset <= TRCVMIDCCTLR1))) {
switch (offset) {
/* 32 bit single control and filter registers */
MAPREG(TRCEVENTCTL0R, eventctrl0);
MAPREG(TRCEVENTCTL1R, eventctrl1);
MAPREG(TRCSTALLCTLR, stall_ctrl);
MAPREG(TRCTSCTLR, ts_ctrl);
MAPREG(TRCSYNCPR, syncfreq);
MAPREG(TRCCCCTLR, ccctlr);
MAPREG(TRCBBCTLR, bb_ctrl);
MAPREG(TRCVICTLR, vinst_ctrl);
MAPREG(TRCVIIECTLR, viiectlr);
MAPREG(TRCVISSCTLR, vissctlr);
MAPREG(TRCVIPCSSCTLR, vipcssctlr);
MAPREG(TRCSEQRSTEVR, seq_rst);
MAPREG(TRCSEQSTR, seq_state);
MAPREG(TRCEXTINSELR, ext_inp);
MAPREG(TRCCIDCCTLR0, ctxid_mask0);
MAPREG(TRCCIDCCTLR1, ctxid_mask1);
MAPREG(TRCVMIDCCTLR0, vmid_mask0);
MAPREG(TRCVMIDCCTLR1, vmid_mask1);
default:
err = -EINVAL;
break;
}
} 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];
else
err = -EINVAL;
} else if ((offset >= TRCSSCCRn(0)) && (offset <= TRCSSPCICRn(7))) {
/* 32 bit, 8 off indexed register sets */
idx = (offset & GENMASK(4, 0)) / 4;
switch (offset & GENMASK(11, 5)) {
MAPREGIDX(TRCSSCCRn(0), ss_ctrl, idx);
MAPREGIDX(TRCSSCSRn(0), ss_status, idx);
MAPREGIDX(TRCSSPCICRn(0), ss_pe_cmp, idx);
default:
err = -EINVAL;
break;
}
} else if ((offset >= TRCCIDCVRn(0)) && (offset <= TRCVMIDCVRn(7))) {
/* 64 bit, 8 off indexed register sets */
idx = (offset & GENMASK(5, 0)) / 8;
switch (offset & GENMASK(11, 6)) {
MAPREGIDX(TRCCIDCVRn(0), ctxid_pid, idx);
MAPREGIDX(TRCVMIDCVRn(0), vmid_val, idx);
default:
err = -EINVAL;
break;
}
} 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];
else
err = -EINVAL;
} 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;
switch (offset & GENMASK(11, 7)) {
MAPREGIDX(TRCACVRn(0), addr_val, idx);
MAPREGIDX(TRCACATRn(0), addr_acc, idx);
default:
err = -EINVAL;
break;
}
} 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;
switch (offset & GENMASK(11, 4)) {
MAPREGIDX(TRCCNTRLDVRn(0), cntrldvr, idx);
MAPREGIDX(TRCCNTCTLRn(0), cntr_ctrl, idx);
MAPREGIDX(TRCCNTVRn(0), cntr_val, idx);
default:
err = -EINVAL;
break;
}
} else {
err = -EINVAL;
}
return err;
+}
+/**
- etm4_cfg_load_feature - load a feature into a device instance.
- @csdev: An ETMv4 CoreSight device.
- @feat_desc: The static feature descriptor to be loaded.
- The function will load a feature instance into the device, based on the
- supplied descriptor. The descriptor will be checked to ensure a valid
- feature can be loaded for this ETMv4 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.
- */
+static int etm4_cfg_load_feature(struct coresight_device *csdev,
const struct cs_cfg_feature_desc *feat_desc)
+{
struct device *dev = csdev->dev.parent;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev);
struct cs_cfg_feature *feat;
u32 offset;
int i = 0, err = 0;
feat = devm_kzalloc(dev, sizeof(struct cs_cfg_feature), GFP_KERNEL);
if (!feat)
return -ENOMEM;
feat->desc = feat_desc;
feat->dev_spinlock = &drvdata->spinlock;
feat->csdev = csdev;
/* count the params regs and allocate space. */
while (feat_desc->params[i++].name)
feat->nr_params++;
i = 0;
while (feat_desc->regs[i++].flags)
feat->nr_regs++;
feat->params = devm_kcalloc(dev, feat->nr_params,
sizeof(struct cs_cfg_parameter),
GFP_KERNEL);
if (!feat->params)
return -ENOMEM;
feat->regs = devm_kcalloc(dev, feat->nr_regs,
sizeof(struct cs_cfg_reg), GFP_KERNEL);
if (!feat->regs)
return -ENOMEM;
/* load the parameters default values */
for (i = 0; i < feat->nr_params; i++)
feat->params[i].feat = feat;
/* process the register descriptions */
for (i = 0; i < feat->nr_regs; i++) {
offset = feat_desc->regs[i].flags & CS_CFG_REG_ID_MASK;
err = etm4_cfg_map_reg_offset(drvdata, &feat->regs[i], offset);
if (err)
return err;
}
/* set sysfs representation of the feature */
err = coresight_cfg_sysfs_add_grp(feat);
/* add the feature to the device list and init default values */
if (!err) {
coresight_cfg_list_add_feat(feat);
coresight_cfg_set_def_ops(feat);
feat->ops.reset(feat);
}
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 cs_cfg_match_info cfg_info;
struct cs_cfg_dev_feat_ops ops;
cfg_info.dev_name = dev_name;
cfg_info.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 56aed38cd0fa..3a58f835eb63 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); @@ -320,12 +322,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;
@@ -383,6 +388,13 @@ static int etm4_parse_event_config(struct etmv4_drvdata *drvdata, /* bit[12], Return stack enable bit */ config->cfg |= BIT(12);
/* set any selected configuration */
if (attr->config2 & BIT(CSSYS_BIT_CONFIG_SEL)) {
cfg_id = (u32)attr->config2;
preset = (attr->config2 >> 32) & 0xF;
If we follow my previous suggestion then the above would look like:
preset = (u32)attr->config1 & 0xF; cfg_id = attr->config2 >> 32;
Just shifting by 32 is obvious when you have this set in mind but insanely difficult to understand for someone trying to figure out what we did. You can use a hard coded value but add a comment that clearly describe what is happening and also reference the PMU_FORMAT_ATTR(configid) at the top of the file.
OK will comment / adjust accordingly & have followed your previous idea..
ret = coresight_cfg_enable_dev_config(csdev, cfg_id, preset);
}
out: return ret; } @@ -399,7 +411,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 */
@@ -415,6 +427,8 @@ static int etm4_enable_sysfs(struct coresight_device *csdev) struct etm4_enable_arg arg = { }; int ret;
coresight_cfg_set_enabled_feats(csdev);
Above in etm4_parse_event_config() function coresight_cfg_enable_dev_config() is used, which implies that when using the perf interface configurations are used. But here coresight_cfg_set_enabled_feats() is called and as such from sysfs features are used.
I think it would be best to use configurations for both perf and sysfs to avoid confusion.
The key difference here is that perf can only ever select a configuration. Because sysfs./ configfs is more flexible it is possible for sysfs to activate a feature on an individual device outside of the concept of a system configuration. The thought here being that a feature can be used, perhaps alongside some other specific programming in sysfs to find a combination that works for a given task. This allows a user to try out things which may end up being used later as a proper configuration.
You bring up a good point - I understand the logic. I would add a comment (pretty much what you wrote above) so we avoid questioning our thought process a year from now.
Thanks
Mike
Thanks, Mathieu
spin_lock(&drvdata->spinlock); /*
@@ -529,11 +543,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 & BIT(CSSYS_BIT_CONFIG_SEL))
coresight_cfg_disable_dev_config(csdev); /* * Check if the start/stop logic was active when the unit was stopped.
@@ -568,6 +585,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);
coresight_cfg_save_enabled_feats(csdev); cpus_read_unlock(); dev_dbg(&csdev->dev, "ETM tracing disabled\n");
@@ -1519,6 +1537,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);
@@ -1571,6 +1596,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 b673e738bc9a..ec182544a064 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);
coresight_cfg_reset_feats(to_coresight_device(dev));
return size;
} static DEVICE_ATTR_WO(reset); -- 2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
Preload set of configurations.
Signed-off-by: Mike Leach mike.leach@linaro.org --- drivers/hwtracing/coresight/Makefile | 3 +- .../coresight/coresight-cfg-preload.c | 165 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-core.c | 7 + .../hwtracing/coresight/coresight-syscfg.h | 1 + 4 files changed, 175 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 5723094b2b69..8914be6b254c 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..77b477b868d0 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cfg-preload.c @@ -0,0 +1,165 @@ +// 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 cs_cfg_parameter_desc strobe_params[] = { + { + .name = "window", + .value = 5000, + }, + { + .name = "period", + .value = 10000, + }, + { 0 }, +}; + +static struct cs_cfg_reg_desc strobe_regs[] = { + /* resource selectors */ + { + .flags = STRB_REG_SEL | TRCRSCTLRn(2), + .value = { + .val32 = 0x20001, + }, + }, + { + .flags = STRB_REG_SEQ | TRCRSCTLRn(3), + .value = { + .val32 = 0x20002, + } + }, + /* strobe window counter 0 - reload from param 0 */ + { + .flags = STRB_REG_CTR_RB | TRCCNTVRn(0), + }, + { + .flags = STRB_REG_CTR_PRM | TRCCNTRLDVRn(0), + .value = { + .val32 = 0, + }, + }, + { + .flags = STRB_REG_CTR | TRCCNTCTLRn(0), + .value = { + .val32 = 0x10001, + }, + }, + /* strobe period counter 1 - reload from param 1 */ + { + .flags = STRB_REG_CTR_RB | TRCCNTVRn(1), + }, + { + .flags = STRB_REG_CTR_PRM | TRCCNTRLDVRn(1), + .value = { + .val32 = 1, + }, + }, + { + .flags = STRB_REG_CTR | TRCCNTCTLRn(1), + .value = { + .val32 = 0x8102, + }, + }, + /* sequencer */ + { + .flags = STRB_REG_SEQ | TRCSEQEVRn(0), + .value = { + .val32 = 0x0081, + }, + }, + { + .flags = STRB_REG_SEQ | TRCSEQEVRn(1), + .value = { + .val32 = 0x0000, + }, + }, + /* view-inst */ + { + .flags = STRB_REG_VI | TRCVICTLR, + .value = { + .val32 = 0x0003, + .mask32 = 0x0003, + }, + }, + /* end of regs */ + { 0 }, +}; + +static struct cs_cfg_feature_desc strobe = { + .name = "strobing", + .brief = "Generate periodic trace capture windows.", + .match_flags = CS_CFG_MATCH_CLASS_SRC_ETM4, + .params = strobe_params, + .regs = strobe_regs, +}; + +static struct cs_cfg_feature_desc *preload_feats[] = { + &strobe, + 0 +}; + +/* create an autofdo configuration */ + +/* we will provide 2 sets of preset parameter values */ +#define AFDO_NR_PRESETS 2 +/* the total number of parameters in used features */ +#define AFDO_NR_PARAM_SUM 2 + +#define AFDO_MATCH_STROBING (CS_CFG_MATCH_INST_ANY | CS_CFG_MATCH_CLASS_SRC_ETM4) + +static struct cs_cfg_uses_feat_desc afdo_uses[] = { + { + .name = "strobing", + .nr_params = 2, + .match = { + .flags = AFDO_MATCH_STROBING, + }, + }, +}; + +static u64 afdo_presets[AFDO_NR_PRESETS][AFDO_NR_PARAM_SUM] = { + { 10000, 5000 }, + { 5000, 5000 }, +}; + + +static struct cs_cfg_config_desc afdo = { + .name = "autofdo", + .brief = "Setup ETMs with strobing for autofdo", + .nr_uses = sizeof(afdo_uses) / sizeof(struct cs_cfg_uses_feat_desc), + .uses = afdo_uses, + .nr_presets = AFDO_NR_PRESETS, + .nr_total_params = AFDO_NR_PARAM_SUM, + .presets = &afdo_presets[0][0], +}; + +static struct cs_cfg_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 91f1fbd7d51d..7158d5a46b93 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -1701,9 +1701,16 @@ static int __init coresight_init(void) goto exit_perf_clear;
ret = cscfg_create_device(); + if (ret) + goto exit_cscfg_driver; + + /* preload builtin configurations */ + ret = cscfg_preload(); if (!ret) return 0;
+ cscfg_clear_device(); +exit_cscfg_driver: cscfg_driver_exit(); exit_perf_clear: etm_perf_exit(); diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 30dc12a7ecaa..b3a1c246dd33 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -77,6 +77,7 @@ int cscfg_create_device(void); void cscfg_clear_device(void); int __init cscfg_driver_init(void); void cscfg_driver_exit(void); +int cscfg_preload(void);
/* syscfg external API */ int cscfg_load_config_sets(struct cs_cfg_config_desc **cfg_descs,
On Thu, Aug 27, 2020 at 03:34:11PM +0100, Mike Leach wrote:
Preload set of configurations.
A better description is needed here.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 3 +- .../coresight/coresight-cfg-preload.c | 165 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-core.c | 7 + .../hwtracing/coresight/coresight-syscfg.h | 1 + 4 files changed, 175 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 5723094b2b69..8914be6b254c 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..77b477b868d0 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cfg-preload.c @@ -0,0 +1,165 @@ +// 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 cs_cfg_parameter_desc strobe_params[] = {
- {
.name = "window",
.value = 5000,
- },
- {
.name = "period",
.value = 10000,
Why do parameters have an initial value? Isn't that what presets are for? To me it seems like there is three ways to have initial values: parameters, register descriptors and presets. Going down to a single one, probably presets, would make things more simple.
I am done reviewing this set.
Thanks for the patience, Mathieu
- },
- { 0 },
+};
+static struct cs_cfg_reg_desc strobe_regs[] = {
- /* resource selectors */
- {
.flags = STRB_REG_SEL | TRCRSCTLRn(2),
.value = {
.val32 = 0x20001,
},
- },
- {
.flags = STRB_REG_SEQ | TRCRSCTLRn(3),
.value = {
.val32 = 0x20002,
}
- },
- /* strobe window counter 0 - reload from param 0 */
- {
.flags = STRB_REG_CTR_RB | TRCCNTVRn(0),
- },
- {
.flags = STRB_REG_CTR_PRM | TRCCNTRLDVRn(0),
.value = {
.val32 = 0,
},
- },
- {
.flags = STRB_REG_CTR | TRCCNTCTLRn(0),
.value = {
.val32 = 0x10001,
},
- },
- /* strobe period counter 1 - reload from param 1 */
- {
.flags = STRB_REG_CTR_RB | TRCCNTVRn(1),
- },
- {
.flags = STRB_REG_CTR_PRM | TRCCNTRLDVRn(1),
.value = {
.val32 = 1,
},
- },
- {
.flags = STRB_REG_CTR | TRCCNTCTLRn(1),
.value = {
.val32 = 0x8102,
},
- },
- /* sequencer */
- {
.flags = STRB_REG_SEQ | TRCSEQEVRn(0),
.value = {
.val32 = 0x0081,
},
- },
- {
.flags = STRB_REG_SEQ | TRCSEQEVRn(1),
.value = {
.val32 = 0x0000,
},
- },
- /* view-inst */
- {
.flags = STRB_REG_VI | TRCVICTLR,
.value = {
.val32 = 0x0003,
.mask32 = 0x0003,
},
- },
- /* end of regs */
- { 0 },
+};
+static struct cs_cfg_feature_desc strobe = {
- .name = "strobing",
- .brief = "Generate periodic trace capture windows.",
- .match_flags = CS_CFG_MATCH_CLASS_SRC_ETM4,
- .params = strobe_params,
- .regs = strobe_regs,
+};
+static struct cs_cfg_feature_desc *preload_feats[] = {
- &strobe,
- 0
+};
+/* create an autofdo configuration */
+/* we will provide 2 sets of preset parameter values */ +#define AFDO_NR_PRESETS 2 +/* the total number of parameters in used features */ +#define AFDO_NR_PARAM_SUM 2
+#define AFDO_MATCH_STROBING (CS_CFG_MATCH_INST_ANY | CS_CFG_MATCH_CLASS_SRC_ETM4)
+static struct cs_cfg_uses_feat_desc afdo_uses[] = {
- {
.name = "strobing",
.nr_params = 2,
.match = {
.flags = AFDO_MATCH_STROBING,
},
- },
+};
+static u64 afdo_presets[AFDO_NR_PRESETS][AFDO_NR_PARAM_SUM] = {
- { 10000, 5000 },
- { 5000, 5000 },
+};
+static struct cs_cfg_config_desc afdo = {
- .name = "autofdo",
- .brief = "Setup ETMs with strobing for autofdo",
- .nr_uses = sizeof(afdo_uses) / sizeof(struct cs_cfg_uses_feat_desc),
- .uses = afdo_uses,
- .nr_presets = AFDO_NR_PRESETS,
- .nr_total_params = AFDO_NR_PARAM_SUM,
- .presets = &afdo_presets[0][0],
+};
+static struct cs_cfg_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 91f1fbd7d51d..7158d5a46b93 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -1701,9 +1701,16 @@ static int __init coresight_init(void) goto exit_perf_clear; ret = cscfg_create_device();
- if (ret)
goto exit_cscfg_driver;
- /* preload builtin configurations */
- ret = cscfg_preload(); if (!ret) return 0;
- cscfg_clear_device();
+exit_cscfg_driver: cscfg_driver_exit(); exit_perf_clear: etm_perf_exit(); diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 30dc12a7ecaa..b3a1c246dd33 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -77,6 +77,7 @@ int cscfg_create_device(void); void cscfg_clear_device(void); int __init cscfg_driver_init(void); void cscfg_driver_exit(void); +int cscfg_preload(void); /* syscfg external API */ int cscfg_load_config_sets(struct cs_cfg_config_desc **cfg_descs, -- 2.17.1
On Tue, 13 Oct 2020 at 15:24, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Thu, Aug 27, 2020 at 03:34:11PM +0100, Mike Leach wrote:
Preload set of configurations.
A better description is needed here.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 3 +- .../coresight/coresight-cfg-preload.c | 165 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-core.c | 7 + .../hwtracing/coresight/coresight-syscfg.h | 1 + 4 files changed, 175 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 5723094b2b69..8914be6b254c 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..77b477b868d0 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cfg-preload.c @@ -0,0 +1,165 @@ +// 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 cs_cfg_parameter_desc strobe_params[] = {
{
.name = "window",
.value = 5000,
},
{
.name = "period",
.value = 10000,
Why do parameters have an initial value? Isn't that what presets are for? To me it seems like there is three ways to have initial values: parameters, register descriptors and presets. Going down to a single one, probably presets, would make things more simple.
I am done reviewing this set.
I forgot, the next revision will need to CC the linux-arm-kernel mailing list.
Thanks for the patience, Mathieu
},
{ 0 },
+};
+static struct cs_cfg_reg_desc strobe_regs[] = {
/* resource selectors */
{
.flags = STRB_REG_SEL | TRCRSCTLRn(2),
.value = {
.val32 = 0x20001,
},
},
{
.flags = STRB_REG_SEQ | TRCRSCTLRn(3),
.value = {
.val32 = 0x20002,
}
},
/* strobe window counter 0 - reload from param 0 */
{
.flags = STRB_REG_CTR_RB | TRCCNTVRn(0),
},
{
.flags = STRB_REG_CTR_PRM | TRCCNTRLDVRn(0),
.value = {
.val32 = 0,
},
},
{
.flags = STRB_REG_CTR | TRCCNTCTLRn(0),
.value = {
.val32 = 0x10001,
},
},
/* strobe period counter 1 - reload from param 1 */
{
.flags = STRB_REG_CTR_RB | TRCCNTVRn(1),
},
{
.flags = STRB_REG_CTR_PRM | TRCCNTRLDVRn(1),
.value = {
.val32 = 1,
},
},
{
.flags = STRB_REG_CTR | TRCCNTCTLRn(1),
.value = {
.val32 = 0x8102,
},
},
/* sequencer */
{
.flags = STRB_REG_SEQ | TRCSEQEVRn(0),
.value = {
.val32 = 0x0081,
},
},
{
.flags = STRB_REG_SEQ | TRCSEQEVRn(1),
.value = {
.val32 = 0x0000,
},
},
/* view-inst */
{
.flags = STRB_REG_VI | TRCVICTLR,
.value = {
.val32 = 0x0003,
.mask32 = 0x0003,
},
},
/* end of regs */
{ 0 },
+};
+static struct cs_cfg_feature_desc strobe = {
.name = "strobing",
.brief = "Generate periodic trace capture windows.",
.match_flags = CS_CFG_MATCH_CLASS_SRC_ETM4,
.params = strobe_params,
.regs = strobe_regs,
+};
+static struct cs_cfg_feature_desc *preload_feats[] = {
&strobe,
0
+};
+/* create an autofdo configuration */
+/* we will provide 2 sets of preset parameter values */ +#define AFDO_NR_PRESETS 2 +/* the total number of parameters in used features */ +#define AFDO_NR_PARAM_SUM 2
+#define AFDO_MATCH_STROBING (CS_CFG_MATCH_INST_ANY | CS_CFG_MATCH_CLASS_SRC_ETM4)
+static struct cs_cfg_uses_feat_desc afdo_uses[] = {
{
.name = "strobing",
.nr_params = 2,
.match = {
.flags = AFDO_MATCH_STROBING,
},
},
+};
+static u64 afdo_presets[AFDO_NR_PRESETS][AFDO_NR_PARAM_SUM] = {
{ 10000, 5000 },
{ 5000, 5000 },
+};
+static struct cs_cfg_config_desc afdo = {
.name = "autofdo",
.brief = "Setup ETMs with strobing for autofdo",
.nr_uses = sizeof(afdo_uses) / sizeof(struct cs_cfg_uses_feat_desc),
.uses = afdo_uses,
.nr_presets = AFDO_NR_PRESETS,
.nr_total_params = AFDO_NR_PARAM_SUM,
.presets = &afdo_presets[0][0],
+};
+static struct cs_cfg_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 91f1fbd7d51d..7158d5a46b93 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -1701,9 +1701,16 @@ static int __init coresight_init(void) goto exit_perf_clear;
ret = cscfg_create_device();
if (ret)
goto exit_cscfg_driver;
/* preload builtin configurations */
ret = cscfg_preload(); if (!ret) return 0;
cscfg_clear_device();
+exit_cscfg_driver: cscfg_driver_exit(); exit_perf_clear: etm_perf_exit(); diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 30dc12a7ecaa..b3a1c246dd33 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -77,6 +77,7 @@ int cscfg_create_device(void); void cscfg_clear_device(void); int __init cscfg_driver_init(void); void cscfg_driver_exit(void); +int cscfg_preload(void);
/* syscfg external API */ int cscfg_load_config_sets(struct cs_cfg_config_desc **cfg_descs, -- 2.17.1
Hi Mathieu,
On Tue, 13 Oct 2020 at 22:24, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Thu, Aug 27, 2020 at 03:34:11PM +0100, Mike Leach wrote:
Preload set of configurations.
A better description is needed here.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 3 +- .../coresight/coresight-cfg-preload.c | 165 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-core.c | 7 + .../hwtracing/coresight/coresight-syscfg.h | 1 + 4 files changed, 175 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 5723094b2b69..8914be6b254c 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..77b477b868d0 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cfg-preload.c @@ -0,0 +1,165 @@ +// 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 cs_cfg_parameter_desc strobe_params[] = {
{
.name = "window",
.value = 5000,
},
{
.name = "period",
.value = 10000,
Why do parameters have an initial value? Isn't that what presets are for? To me it seems like there is three ways to have initial values: parameters, register descriptors and presets. Going down to a single one, probably presets, would make things more simple.
parameters, presets and register values have 3 distinct and different jobs. 1) registers - straight up write this register with the value I told you. 2) parameters - these values get loaded into a register when a feature is enabled on a device instance. The value can be what the user set it to, or if they do not set it, then the value that is declared in the initial descriptor is used. The key here is that the register declaration - i.e. the register the parameter is copied into, uses a form where the value is the index of the parameter. hence the parameter most have the real value used. 3) presets - these are easily selectable setys of parameter values for a configuration initiated from the perf command line. So will override the default / current user selected value for a given trace run.
The v3 set contains the initial draft of some documentation so hopefully the concepts will be easier to follow.
I am done reviewing this set.
Thanks for the review. Appreciate it was quite a large set to look at.
Regards
Mike
Thanks for the patience, Mathieu
},
{ 0 },
+};
+static struct cs_cfg_reg_desc strobe_regs[] = {
/* resource selectors */
{
.flags = STRB_REG_SEL | TRCRSCTLRn(2),
.value = {
.val32 = 0x20001,
},
},
{
.flags = STRB_REG_SEQ | TRCRSCTLRn(3),
.value = {
.val32 = 0x20002,
}
},
/* strobe window counter 0 - reload from param 0 */
{
.flags = STRB_REG_CTR_RB | TRCCNTVRn(0),
},
{
.flags = STRB_REG_CTR_PRM | TRCCNTRLDVRn(0),
.value = {
.val32 = 0,
},
},
{
.flags = STRB_REG_CTR | TRCCNTCTLRn(0),
.value = {
.val32 = 0x10001,
},
},
/* strobe period counter 1 - reload from param 1 */
{
.flags = STRB_REG_CTR_RB | TRCCNTVRn(1),
},
{
.flags = STRB_REG_CTR_PRM | TRCCNTRLDVRn(1),
.value = {
.val32 = 1,
},
},
{
.flags = STRB_REG_CTR | TRCCNTCTLRn(1),
.value = {
.val32 = 0x8102,
},
},
/* sequencer */
{
.flags = STRB_REG_SEQ | TRCSEQEVRn(0),
.value = {
.val32 = 0x0081,
},
},
{
.flags = STRB_REG_SEQ | TRCSEQEVRn(1),
.value = {
.val32 = 0x0000,
},
},
/* view-inst */
{
.flags = STRB_REG_VI | TRCVICTLR,
.value = {
.val32 = 0x0003,
.mask32 = 0x0003,
},
},
/* end of regs */
{ 0 },
+};
+static struct cs_cfg_feature_desc strobe = {
.name = "strobing",
.brief = "Generate periodic trace capture windows.",
.match_flags = CS_CFG_MATCH_CLASS_SRC_ETM4,
.params = strobe_params,
.regs = strobe_regs,
+};
+static struct cs_cfg_feature_desc *preload_feats[] = {
&strobe,
0
+};
+/* create an autofdo configuration */
+/* we will provide 2 sets of preset parameter values */ +#define AFDO_NR_PRESETS 2 +/* the total number of parameters in used features */ +#define AFDO_NR_PARAM_SUM 2
+#define AFDO_MATCH_STROBING (CS_CFG_MATCH_INST_ANY | CS_CFG_MATCH_CLASS_SRC_ETM4)
+static struct cs_cfg_uses_feat_desc afdo_uses[] = {
{
.name = "strobing",
.nr_params = 2,
.match = {
.flags = AFDO_MATCH_STROBING,
},
},
+};
+static u64 afdo_presets[AFDO_NR_PRESETS][AFDO_NR_PARAM_SUM] = {
{ 10000, 5000 },
{ 5000, 5000 },
+};
+static struct cs_cfg_config_desc afdo = {
.name = "autofdo",
.brief = "Setup ETMs with strobing for autofdo",
.nr_uses = sizeof(afdo_uses) / sizeof(struct cs_cfg_uses_feat_desc),
.uses = afdo_uses,
.nr_presets = AFDO_NR_PRESETS,
.nr_total_params = AFDO_NR_PARAM_SUM,
.presets = &afdo_presets[0][0],
+};
+static struct cs_cfg_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 91f1fbd7d51d..7158d5a46b93 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -1701,9 +1701,16 @@ static int __init coresight_init(void) goto exit_perf_clear;
ret = cscfg_create_device();
if (ret)
goto exit_cscfg_driver;
/* preload builtin configurations */
ret = cscfg_preload(); if (!ret) return 0;
cscfg_clear_device();
+exit_cscfg_driver: cscfg_driver_exit(); exit_perf_clear: etm_perf_exit(); diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 30dc12a7ecaa..b3a1c246dd33 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -77,6 +77,7 @@ int cscfg_create_device(void); void cscfg_clear_device(void); int __init cscfg_driver_init(void); void cscfg_driver_exit(void); +int cscfg_preload(void);
/* syscfg external API */ int cscfg_load_config_sets(struct cs_cfg_config_desc **cfg_descs, -- 2.17.1
On Thu, Oct 29, 2020 at 06:50:10PM +0000, Mike Leach wrote:
Hi Mathieu,
On Tue, 13 Oct 2020 at 22:24, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Thu, Aug 27, 2020 at 03:34:11PM +0100, Mike Leach wrote:
Preload set of configurations.
A better description is needed here.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 3 +- .../coresight/coresight-cfg-preload.c | 165 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-core.c | 7 + .../hwtracing/coresight/coresight-syscfg.h | 1 + 4 files changed, 175 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 5723094b2b69..8914be6b254c 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..77b477b868d0 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cfg-preload.c @@ -0,0 +1,165 @@ +// 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 cs_cfg_parameter_desc strobe_params[] = {
{
.name = "window",
.value = 5000,
},
{
.name = "period",
.value = 10000,
Why do parameters have an initial value? Isn't that what presets are for? To me it seems like there is three ways to have initial values: parameters, register descriptors and presets. Going down to a single one, probably presets, would make things more simple.
parameters, presets and register values have 3 distinct and different jobs.
- registers - straight up write this register with the value I told you.
Could those values be part of a preset? If a preset isn't specified then everthing defaults to 0. If that really doesn't make sense to you we can keep things the way they are now and revisit at this set matures.
- parameters - these values get loaded into a register when a feature
is enabled on a device instance. The value can be what the user set it to, or if they do not set it, then the value that is declared in the initial descriptor is used. The key here is that the register declaration - i.e. the register the parameter is copied into, uses a form where the value is the index of the parameter. hence the parameter most have the real value used. 3) presets - these are easily selectable setys of parameter values for a configuration initiated from the perf command line. So will override the default / current user selected value for a given trace run.
The v3 set contains the initial draft of some documentation so hopefully the concepts will be easier to follow.
Ok
I am done reviewing this set.
Thanks for the review. Appreciate it was quite a large set to look at.
Well, I have to commend you for your extreme patience. The work is large but I think you have it down to a minimum - I really don't see what could be sliced off.
Regards
Mike
Thanks for the patience, Mathieu
},
{ 0 },
+};
+static struct cs_cfg_reg_desc strobe_regs[] = {
/* resource selectors */
{
.flags = STRB_REG_SEL | TRCRSCTLRn(2),
.value = {
.val32 = 0x20001,
},
},
{
.flags = STRB_REG_SEQ | TRCRSCTLRn(3),
.value = {
.val32 = 0x20002,
}
},
/* strobe window counter 0 - reload from param 0 */
{
.flags = STRB_REG_CTR_RB | TRCCNTVRn(0),
},
{
.flags = STRB_REG_CTR_PRM | TRCCNTRLDVRn(0),
.value = {
.val32 = 0,
},
},
{
.flags = STRB_REG_CTR | TRCCNTCTLRn(0),
.value = {
.val32 = 0x10001,
},
},
/* strobe period counter 1 - reload from param 1 */
{
.flags = STRB_REG_CTR_RB | TRCCNTVRn(1),
},
{
.flags = STRB_REG_CTR_PRM | TRCCNTRLDVRn(1),
.value = {
.val32 = 1,
},
},
{
.flags = STRB_REG_CTR | TRCCNTCTLRn(1),
.value = {
.val32 = 0x8102,
},
},
/* sequencer */
{
.flags = STRB_REG_SEQ | TRCSEQEVRn(0),
.value = {
.val32 = 0x0081,
},
},
{
.flags = STRB_REG_SEQ | TRCSEQEVRn(1),
.value = {
.val32 = 0x0000,
},
},
/* view-inst */
{
.flags = STRB_REG_VI | TRCVICTLR,
.value = {
.val32 = 0x0003,
.mask32 = 0x0003,
},
},
/* end of regs */
{ 0 },
+};
+static struct cs_cfg_feature_desc strobe = {
.name = "strobing",
.brief = "Generate periodic trace capture windows.",
.match_flags = CS_CFG_MATCH_CLASS_SRC_ETM4,
.params = strobe_params,
.regs = strobe_regs,
+};
+static struct cs_cfg_feature_desc *preload_feats[] = {
&strobe,
0
+};
+/* create an autofdo configuration */
+/* we will provide 2 sets of preset parameter values */ +#define AFDO_NR_PRESETS 2 +/* the total number of parameters in used features */ +#define AFDO_NR_PARAM_SUM 2
+#define AFDO_MATCH_STROBING (CS_CFG_MATCH_INST_ANY | CS_CFG_MATCH_CLASS_SRC_ETM4)
+static struct cs_cfg_uses_feat_desc afdo_uses[] = {
{
.name = "strobing",
.nr_params = 2,
.match = {
.flags = AFDO_MATCH_STROBING,
},
},
+};
+static u64 afdo_presets[AFDO_NR_PRESETS][AFDO_NR_PARAM_SUM] = {
{ 10000, 5000 },
{ 5000, 5000 },
+};
+static struct cs_cfg_config_desc afdo = {
.name = "autofdo",
.brief = "Setup ETMs with strobing for autofdo",
.nr_uses = sizeof(afdo_uses) / sizeof(struct cs_cfg_uses_feat_desc),
.uses = afdo_uses,
.nr_presets = AFDO_NR_PRESETS,
.nr_total_params = AFDO_NR_PARAM_SUM,
.presets = &afdo_presets[0][0],
+};
+static struct cs_cfg_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 91f1fbd7d51d..7158d5a46b93 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -1701,9 +1701,16 @@ static int __init coresight_init(void) goto exit_perf_clear;
ret = cscfg_create_device();
if (ret)
goto exit_cscfg_driver;
/* preload builtin configurations */
ret = cscfg_preload(); if (!ret) return 0;
cscfg_clear_device();
+exit_cscfg_driver: cscfg_driver_exit(); exit_perf_clear: etm_perf_exit(); diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 30dc12a7ecaa..b3a1c246dd33 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -77,6 +77,7 @@ int cscfg_create_device(void); void cscfg_clear_device(void); int __init cscfg_driver_init(void); void cscfg_driver_exit(void); +int cscfg_preload(void);
/* syscfg external API */ int cscfg_load_config_sets(struct cs_cfg_config_desc **cfg_descs, -- 2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
Good day Mike,
Sorry for the lack of responsiveness on this set. It is still in my queue and I am hoping to get to it in the next couple of weeks.
Thanks, Mathieu
On Thu, 27 Aug 2020 at 08:34, Mike Leach mike.leach@linaro.org 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. (at present these default parameters can be altered using sysfs for each individual ETM - but this is under review).
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.)
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.
Applies to coresight/next (5.9-rc1 base) with the coresight module load set [1] applied.
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. e) documentation file.
[1] https://lists.linaro.org/pipermail/coresight/2020-August/004704.html
Mike Leach (8): coresight: syscfg: Initial coresight system configuration coresight: syscfg: Add loading of features and configurations coresight: syscfg: Add registration and feature loading for cs devices coresight: config: Add configuration and feature generic functions perf: cs_etm: update cs_etm processing to allow configuration selection coresight: etm-perf: update to handle configuration selection coresight: etm4x: Add complex configuration handlers to etmv4 coresight: config: Add preloaded configurations
drivers/hwtracing/coresight/Makefile | 6 +- .../coresight/coresight-cfg-preload.c | 165 +++++ .../hwtracing/coresight/coresight-config.c | 565 ++++++++++++++++++ .../hwtracing/coresight/coresight-config.h | 289 +++++++++ drivers/hwtracing/coresight/coresight-core.c | 36 +- .../hwtracing/coresight/coresight-etm-perf.c | 91 ++- .../hwtracing/coresight/coresight-etm-perf.h | 8 +- .../hwtracing/coresight/coresight-etm4x-cfg.c | 226 +++++++ .../hwtracing/coresight/coresight-etm4x-cfg.h | 29 + .../coresight/coresight-etm4x-core.c | 30 +- .../coresight/coresight-etm4x-sysfs.c | 3 + .../hwtracing/coresight/coresight-syscfg.c | 527 ++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 90 +++ include/linux/coresight-pmu.h | 3 + include/linux/coresight.h | 8 + tools/include/linux/coresight-pmu.h | 3 + tools/perf/arch/arm/util/cs-etm.c | 17 +- 17 files changed, 2066 insertions(+), 30 deletions(-) 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.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.h
-- 2.17.1
Good afternoon,
I have started to review this set. I will go through all the patches first to get a better idea of what is going on. From there I'll do another pass where I will post comments.
With this much code and 20 new structures to look at, the process will take me several days.
Thanks, Mathieu
On Thu, Aug 27, 2020 at 03:34:03PM +0100, 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. (at present these default parameters can be altered using sysfs for each individual ETM - but this is under review).
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.)
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.
Applies to coresight/next (5.9-rc1 base) with the coresight module load set [1] applied.
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. e) documentation file.
[1] https://lists.linaro.org/pipermail/coresight/2020-August/004704.html
Mike Leach (8): coresight: syscfg: Initial coresight system configuration coresight: syscfg: Add loading of features and configurations coresight: syscfg: Add registration and feature loading for cs devices coresight: config: Add configuration and feature generic functions perf: cs_etm: update cs_etm processing to allow configuration selection coresight: etm-perf: update to handle configuration selection coresight: etm4x: Add complex configuration handlers to etmv4 coresight: config: Add preloaded configurations
drivers/hwtracing/coresight/Makefile | 6 +- .../coresight/coresight-cfg-preload.c | 165 +++++ .../hwtracing/coresight/coresight-config.c | 565 ++++++++++++++++++ .../hwtracing/coresight/coresight-config.h | 289 +++++++++ drivers/hwtracing/coresight/coresight-core.c | 36 +- .../hwtracing/coresight/coresight-etm-perf.c | 91 ++- .../hwtracing/coresight/coresight-etm-perf.h | 8 +- .../hwtracing/coresight/coresight-etm4x-cfg.c | 226 +++++++ .../hwtracing/coresight/coresight-etm4x-cfg.h | 29 + .../coresight/coresight-etm4x-core.c | 30 +- .../coresight/coresight-etm4x-sysfs.c | 3 + .../hwtracing/coresight/coresight-syscfg.c | 527 ++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 90 +++ include/linux/coresight-pmu.h | 3 + include/linux/coresight.h | 8 + tools/include/linux/coresight-pmu.h | 3 + tools/perf/arch/arm/util/cs-etm.c | 17 +- 17 files changed, 2066 insertions(+), 30 deletions(-) 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.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.h
-- 2.17.1
On Wed, Sep 23, 2020 at 03:14:23PM -0600, Mathieu Poirier wrote:
Good afternoon,
I have started to review this set. I will go through all the patches first to get a better idea of what is going on. From there I'll do another pass where I will post comments.
With this much code and 20 new structures to look at, the process will take me several days.
I am done with the first pass. There are things to improve on, which is always the case with this much code, but as a whole it is holding together well. I am especially happy with how configurations are exported to the PMU's cs_etm directory.
I will start another pass tomorrow where I'll give more specific comments.
Thanks, Mathieu
On Thu, Aug 27, 2020 at 03:34:03PM +0100, 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. (at present these default parameters can be altered using sysfs for each individual ETM - but this is under review).
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.)
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.
Applies to coresight/next (5.9-rc1 base) with the coresight module load set [1] applied.
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. e) documentation file.
[1] https://lists.linaro.org/pipermail/coresight/2020-August/004704.html
Mike Leach (8): coresight: syscfg: Initial coresight system configuration coresight: syscfg: Add loading of features and configurations coresight: syscfg: Add registration and feature loading for cs devices coresight: config: Add configuration and feature generic functions perf: cs_etm: update cs_etm processing to allow configuration selection coresight: etm-perf: update to handle configuration selection coresight: etm4x: Add complex configuration handlers to etmv4 coresight: config: Add preloaded configurations
drivers/hwtracing/coresight/Makefile | 6 +- .../coresight/coresight-cfg-preload.c | 165 +++++ .../hwtracing/coresight/coresight-config.c | 565 ++++++++++++++++++ .../hwtracing/coresight/coresight-config.h | 289 +++++++++ drivers/hwtracing/coresight/coresight-core.c | 36 +- .../hwtracing/coresight/coresight-etm-perf.c | 91 ++- .../hwtracing/coresight/coresight-etm-perf.h | 8 +- .../hwtracing/coresight/coresight-etm4x-cfg.c | 226 +++++++ .../hwtracing/coresight/coresight-etm4x-cfg.h | 29 + .../coresight/coresight-etm4x-core.c | 30 +- .../coresight/coresight-etm4x-sysfs.c | 3 + .../hwtracing/coresight/coresight-syscfg.c | 527 ++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.h | 90 +++ include/linux/coresight-pmu.h | 3 + include/linux/coresight.h | 8 + tools/include/linux/coresight-pmu.h | 3 + tools/perf/arch/arm/util/cs-etm.c | 17 +- 17 files changed, 2066 insertions(+), 30 deletions(-) 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.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.h
-- 2.17.1