Good day,
I like what you did in this set. It took me a while to come to terms with all the new structures but this is something we can address in subsequent revisions if need be. I also found a couple of minor problems but that too can be dealt with later. I would like to discuss 3 mains points:
1) Make the features configurable _and_ modular. Depending on how many features people come up with it may become tedious to carry all that extra code. For the modularity I suggest you take inspiration from the governor model used in the cpufreq subsystem. Governors, such as the performance governor[1], are all modules that get registered with the cpufreq core[2]. From there when a governor is selected[3] the core increases the governor's module count[4], preventing the module from being unloaded while a governor is used.
2) Please explore the possibility of using configfs rather than sysfs. That way users can create their own features without the need to add a new module.
3) Perf sessions need to be able to choose which feature they want to use rather than defaulting to a system wide configuration. If you don't want to deal with that at this stage - something I would certainly understand - simpy don't take features into account from the perf interface.
Thanks, Mathieu
[1]. https://elixir.bootlin.com/linux/latest/source/drivers/cpufreq/cpufreq_perfo... [2]. https://elixir.bootlin.com/linux/latest/source/drivers/cpufreq/cpufreq.c#L23... [3]. https://elixir.bootlin.com/linux/latest/source/drivers/cpufreq/cpufreq.c#L76... [4]. https://elixir.bootlin.com/linux/latest/source/drivers/cpufreq/cpufreq.c#L63...
On Wed, Jun 10, 2020 at 10:13:32AM +0100, Mike Leach wrote:
This set introduces the concept of complex features for CoreSight devices, and adds a feature to ETMv4 to enable strobing of the etm capture.
- Complex Features: These are programming settings for devices, especially
ETM which have many programmable register that can be combined to create complex functionality. Features appear as sub-directories in sysfs, having an enable parameter to set the full program setting.
- ETM strobing. This feature is introduced to ETMv4 to allow the trace
capture to be periodically switched on and off - strobed - to a given mark / space ratio to generate statistical trace data for workflows such as auto-fdo.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 7 +- .../hwtracing/coresight/coresight-config.c | 380 ++++++++++++++++++ .../hwtracing/coresight/coresight-config.h | 156 +++++++ .../hwtracing/coresight/coresight-etm4x-cfg.c | 325 +++++++++++++++ .../hwtracing/coresight/coresight-etm4x-cfg.h | 29 ++ .../coresight/coresight-etm4x-sysfs.c | 3 + drivers/hwtracing/coresight/coresight-etm4x.c | 18 +- drivers/hwtracing/coresight/coresight.c | 1 + include/linux/coresight.h | 2 + 9 files changed, 917 insertions(+), 4 deletions(-) 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
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 19497d1d92bf..b6c28f4cfca7 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -3,7 +3,8 @@ # Makefile for CoreSight drivers. # obj-$(CONFIG_CORESIGHT) += coresight.o coresight-etm-perf.o \
coresight-platform.o coresight-sysfs.o
coresight-platform.o coresight-sysfs.o \
coresight-config.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o \ coresight-tmc-etf.o \ coresight-tmc-etr.o @@ -14,7 +15,9 @@ obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-funnel.o \ obj-$(CONFIG_CORESIGHT_SOURCE_ETM3X) += coresight-etm3x.o coresight-etm-cp14.o \ coresight-etm3x-sysfs.o obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o \
coresight-etm4x-sysfs.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-config.c b/drivers/hwtracing/coresight/coresight-config.c new file mode 100644 index 000000000000..10c2d546ca82 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.c @@ -0,0 +1,380 @@ +// 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 DEFINE_MUTEX(coresight_cfg_mutex);
+/*
- 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;
- 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);
+}
+/*
- 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) +{
- mutex_lock(&coresight_cfg_mutex);
- list_add(&feat->node, &feat->csdev->feat_list);
- mutex_unlock(&coresight_cfg_mutex);
+}
+inline 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;
+}
+inline 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);
+}
+inline void coresight_cfg_init_reg(struct cs_cfg_reg *reg,
const struct cs_cfg_reg_desc *desc)
+{
- reg->value.val64 = desc->value.val64;
+}
+inline void coresight_cfg_init_reg_param(struct cs_cfg_reg *reg, u32 flags,
struct cs_cfg_parameter *param)
+{
- if (flags & CS_CFG_REG_VAL_64BIT)
reg->value.val64 = param->current_value;
- else
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) +{
- int i;
- u32 flags;
- spin_lock(feat->dev_spinlock);
- if (feat->enabled) {
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 ? "Set enabled" : "Skip disabled");
- spin_unlock(feat->dev_spinlock);
- return 0;
+}
+static void cs_cfg_save_on_disable(struct cs_cfg_feature *feat) +{
- int i;
- u32 flags;
- spin_lock(feat->dev_spinlock);
- if (feat->enabled) {
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);
}
- }
- 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];
coresight_cfg_init_reg_param(reg, flags, 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;
+}
+int coresight_cfg_set_feats_on_ena(struct coresight_device *csdev) +{
- struct cs_cfg_feature *feat;
- int err = 0;
- if (list_empty(&csdev->feat_list))
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);
dev_dbg(&csdev->dev, "Feature %s: %s",
feat->desc->name, err ? "Set failed" : "OK");
if (!err)
break;
}
- }
- return err;
+}
+void coresight_cfg_save_feats_on_dis(struct coresight_device *csdev) +{
- struct cs_cfg_feature *feat;
- if (list_empty(&csdev->feat_list))
return;
- list_for_each_entry(feat, &csdev->feat_list, node) {
if (feat->ops.save_on_disable)
feat->ops.save_on_disable(feat);
- }
+}
+void coresight_cfg_reset_feats(struct coresight_device *csdev) +{
- struct cs_cfg_feature *feat;
- if (list_empty(&csdev->feat_list))
return;
- list_for_each_entry(feat, &csdev->feat_list, node) {
if (feat->ops.reset)
feat->ops.reset(feat);
- }
+} diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h new file mode 100644 index 000000000000..ce69ad5d2bbf --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -0,0 +1,156 @@ +/* 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
+/* 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 */
+/**
- Parameter descriptor for a device feature.
- @name: Name of parameter.
- @value: Initial or default value.
- */
+struct cs_cfg_parameter_desc {
- const char *name;
- const 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: flags defining the handling of the register.
- @value: Initial value & optional mask.
- */
+struct cs_cfg_reg_desc {
- const u32 flags;
- const 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.
- @params: list of parameters used - 0 terminated.
- @reg: list of registers used.
- */
+struct cs_cfg_feature_desc {
- const char *name;
- const char *brief;
- struct cs_cfg_parameter_desc *params;
- struct cs_cfg_reg_desc *regs;
+};
+/**
- config parameter instance - part of a loaded feature.
- @feat: parent feature
- @current_value: current value of parameter - may be set by user via
sysfs, or modified during device operation.
- */
+struct cs_cfg_parameter {
- struct cs_cfg_feature *feat;
- u64 current_value;
+};
+/**
- 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;
+};
+/**
- cs_cfg_ops - standard operations for 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_ops {
- int (*set_on_enable)(struct cs_cfg_feature *feat);
- void (*save_on_disable)(struct cs_cfg_feature *feat);
- void (*reset)(struct cs_cfg_feature *feat);
+};
+/**
- Feature instance loaded into a CoreSight device driver.
- @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_ops ops;
+};
+/* coresight config API functions */ +int coresight_cfg_sysfs_add_grp(struct cs_cfg_feature *feat); +int coresight_cfg_set_feats_on_ena(struct coresight_device *csdev); +void coresight_cfg_save_feats_on_dis(struct coresight_device *csdev); +void coresight_cfg_reset_feats(struct coresight_device *csdev); +void coresight_cfg_set_def_ops(struct cs_cfg_feature *feat); +void coresight_cfg_list_add_feat(struct cs_cfg_feature *feat); +void coresight_cfg_set_reg(struct cs_cfg_reg *reg, u32 flags); +void coresight_cfg_save_reg(struct cs_cfg_reg *reg, u32 flags); +void coresight_cfg_init_reg(struct cs_cfg_reg *reg,
const struct cs_cfg_reg_desc *desc);
+void coresight_cfg_init_reg_param(struct cs_cfg_reg *reg, u32 flags,
struct cs_cfg_parameter *param);
+#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c new file mode 100644 index 000000000000..240e0235c130 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c @@ -0,0 +1,325 @@ +// 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"
+/* built 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 = 1000,
- },
- {
.name = "period",
.value = 10000,
- },
- { 0 },
+};
+static struct cs_cfg_reg_desc strob_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.",
- .params = strobe_params,
- .regs = strob_regs,
+};
+static struct cs_cfg_feature_desc *built_in_feats[] = {
- &strobe,
- 0
+};
+/**
- 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.
- */
+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;
+}
+/* load up the list of builtin features */ +int etm4_cfg_load_builtins(struct coresight_device *csdev) +{
- int idx = 0, err = 0;
- while (built_in_feats[idx] && !err)
err = etm4_cfg_load_feature(csdev, built_in_feats[idx++]);
- return err;
+} diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.h b/drivers/hwtracing/coresight/coresight-etm4x-cfg.h new file mode 100644 index 000000000000..703657cac2fc --- /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"
+/* 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
+/* ETM4 configuration handlers */ +int etm4_cfg_load_builtins(struct coresight_device *csdev);
+#endif /* _CORESIGHT_CORESIGHT_ETM4X_CFG_H */ 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); diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c index 60a5133d801c..e69dbcf5cd4d 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.c +++ b/drivers/hwtracing/coresight/coresight-etm4x.c @@ -34,6 +34,7 @@ #include "coresight-etm4x.h" #include "coresight-etm-perf.h" +#include "coresight-etm4x-cfg.h" static int boot_enable; module_param(boot_enable, int, 0444); @@ -320,10 +321,11 @@ 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;
@@ -383,6 +385,9 @@ static int etm4_parse_event_config(struct etmv4_drvdata *drvdata, /* bit[12], Return stack enable bit */ config->cfg |= BIT(12);
- /* set any enabled features */
- ret = coresight_cfg_set_feats_on_ena(csdev);
out: return ret; } @@ -399,7 +404,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 +420,8 @@ static int etm4_enable_sysfs(struct coresight_device *csdev) struct etm4_enable_arg arg = { }; int ret;
- coresight_cfg_set_feats_on_ena(csdev);
- spin_lock(&drvdata->spinlock);
/* @@ -532,6 +539,7 @@ static int etm4_disable_perf(struct coresight_device *csdev, return -EINVAL; etm4_disable_hw(drvdata);
- coresight_cfg_save_feats_on_dis(csdev);
/* * Check if the start/stop logic was active when the unit was stopped. @@ -566,6 +574,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_feats_on_dis(csdev); cpus_read_unlock();
dev_dbg(&csdev->dev, "ETM tracing disabled\n"); @@ -1510,6 +1519,11 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id) goto err_arch_supported; }
- /* load builtin features */
- ret = etm4_cfg_load_builtins(drvdata->csdev);
- if (ret)
goto err_arch_supported;
- pm_runtime_put(&adev->dev); dev_info(&drvdata->csdev->dev, "CPU%d: ETM v%d.%d initialized\n", drvdata->cpu, drvdata->arch >> 4, drvdata->arch & 0xf);
diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index f3efbb3b2b4d..ac16d96124f6 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -1335,6 +1335,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc) ret = coresight_fixup_orphan_conns(csdev); if (!ret) cti_add_assoc_to_csdev(csdev);
- INIT_LIST_HEAD(&csdev->feat_list);
mutex_unlock(&coresight_mutex); if (ret) { diff --git a/include/linux/coresight.h b/include/linux/coresight.h index e3e9f0e3a878..0e8d529282dd 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -204,6 +204,8 @@ struct coresight_device { /* sysfs links between components */ int nr_links; bool has_conns_grp;
- /* feature list */
- struct list_head feat_list;
}; /* -- 2.17.1