CTIs are defined in the device tree and associated with other CoreSight devices. The core CoreSight code has been modified to enable the registration of the CTI devices on the same bus as the other CoreSight components, but as these are not actually trace generation / capture devices, they are not part of the Coresight path when generating trace.
However, the definition of the standard CoreSight device has been extended to include a reference to an associated CTI device, and the enable / disable trace path operations will auto enable/disable any associated CTI devices at the same time.
Programming is at present via sysfs - a full API is provided to utilise the hardware capabilities. As CTI devices are unprogrammed by default, the auto enable describe above will have no effect until explicit programming takes place.
A set of device tree bindings specific to the CTI topology has been defined. The driver accesses these in a platform agnostic manner, so ACPI bindings can be added later, once they have been agreed and defined for the CTI device.
Documentation has been updated to describe both the CTI hardware, its use and programming in sysfs, and the new dts bindings required.
Tested on DB410 board, applies on coresight/next tree - 5.3-rc1 based.
Changes since v3: * After discussion on CS mailing list, each CTI connection has a triggers<N> sysfs directory with name and trigger signals listed for the connection. * Initial code for creating sysfs links between CoreSight components is introduced and implementation for CTI provided. This allows exploration of the CoreSight topology within the sysfs infrastructure. Patches for links between other CoreSight components to follow. * Power management - CPU hotplug and idle omitted from this set as ongoing developments may define required direction. Additional patch set to follow. * Multiple fixes applied as requested by reviewers esp. Matthieu, Suzuki and Leo.
Changes since v2: Updates to allow for new features on coresight/next and feedback from Mathieu and Leo.
1) Rebase and restructuring to apply on top of ACPI support patch set, currently on coresight/next. of_coresight_cti has been renamed to coresight-cti-platform and device tree bindings added to this but accessed in a platform agnostic manner using fwnode for later ACPI support to be added. 2) Split the sysfs patch info a series of functional patches. 3) Revised the refcount and enabling support. 4) Adopted the generic naming protocol - CTIs are either cti_cpuN or cti_sysM 5) Various minor presentation /checkpatch issues highlighted in feedback. 6) revised CPU hotplug to cover missing cases needed by ETM.
Changes since v1: 1) Significant restructuring of the source code. Adds cti-sysfs file and cti device tree file. Patches add per feature rather than per source file. 2) CPU type power event handling for hotplug moved to CoreSight core, with generic registration interface provided for all CPU bound CS devices to use. 3) CTI signal interconnection details in sysfs now generated dynamically from connection lists in driver. This to fix issue with multi-line sysfs output in previous version. 4) Full device tree bindings for DB410 and Juno provided (to the extent that CTI information is available). 5) AMBA driver update for UCI IDs are now upstream so no longer included in this set.
Mike Leach (15): coresight: cti: Initial CoreSight CTI Driver coresight: cti: Add sysfs coresight mgmt reg access. coresight: cti: Add sysfs access to program function regs coresight: cti: Add sysfs trigger / channel programming API dt-bindings: arm: Adds CoreSight CTI hardware definitions. coresight: cti: Add device tree support for v8 arch CTI coresight: cti: Add device tree support for custom CTI. coresight: cti: Enable CTI associated with devices. coresight: cti: Add connection information to sysfs coresight: Add generic sysfs link creation functions. coresight: cti: Add in sysfs links to other coresight devices. dt-bindings: qcom: Add CTI options for qcom msm8916 dt-bindings: arm: Juno platform - add CTI entries to device tree. docs: coresight: Update documentation for CoreSight to cover CTI. docs: sysfs: coresight: Add sysfs documentation for CTI
.../testing/sysfs-bus-coresight-devices-cti | 231 ++++ .../bindings/arm/coresight-ect-cti.txt | 396 ++++++ .../devicetree/bindings/arm/coresight.txt | 7 + Documentation/trace/coresight-ect.txt | 164 +++ Documentation/trace/coresight.txt | 7 + MAINTAINERS | 3 + arch/arm64/boot/dts/arm/juno-base.dtsi | 149 +- arch/arm64/boot/dts/arm/juno-cs-r1r2.dtsi | 31 +- arch/arm64/boot/dts/arm/juno-r1.dts | 25 + arch/arm64/boot/dts/arm/juno-r2.dts | 25 + arch/arm64/boot/dts/arm/juno.dts | 25 + arch/arm64/boot/dts/qcom/msm8916.dtsi | 85 +- drivers/hwtracing/coresight/Kconfig | 12 + drivers/hwtracing/coresight/Makefile | 4 + .../coresight/coresight-cti-platform.c | 431 ++++++ .../hwtracing/coresight/coresight-cti-sysfs.c | 1199 +++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.c | 763 +++++++++++ drivers/hwtracing/coresight/coresight-cti.h | 238 ++++ .../hwtracing/coresight/coresight-platform.c | 23 + drivers/hwtracing/coresight/coresight-priv.h | 10 + drivers/hwtracing/coresight/coresight.c | 133 +- include/dt-bindings/arm/coresight-cti-dt.h | 36 + include/linux/coresight.h | 46 + 23 files changed, 4029 insertions(+), 14 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-bus-coresight-devices-cti create mode 100644 Documentation/devicetree/bindings/arm/coresight-ect-cti.txt create mode 100644 Documentation/trace/coresight-ect.txt create mode 100644 drivers/hwtracing/coresight/coresight-cti-platform.c create mode 100644 drivers/hwtracing/coresight/coresight-cti-sysfs.c create mode 100644 drivers/hwtracing/coresight/coresight-cti.c create mode 100644 drivers/hwtracing/coresight/coresight-cti.h create mode 100644 include/dt-bindings/arm/coresight-cti-dt.h
This introduces a baseline CTI driver and associated configuration files.
Uses the platform agnostic naming standard for CoreSight devices, along with a generic platform probing method that currently supports device tree descriptions, but allows for the ACPI bindings to be added once these have been defined for the CTI devices.
Driver will probe for the device on the AMBA bus, and load the CTI driver on CoreSight ID match to CTI IDs in tables.
Initial sysfs support for enable / disable provided.
Default CTI interconnection data is generated based on hardware register signal counts, with no additional connection information.
Signed-off-by: Mike Leach mike.leach@linaro.org --- drivers/hwtracing/coresight/Kconfig | 12 + drivers/hwtracing/coresight/Makefile | 4 + .../coresight/coresight-cti-platform.c | 75 +++ .../hwtracing/coresight/coresight-cti-sysfs.c | 72 +++ drivers/hwtracing/coresight/coresight-cti.c | 451 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.h | 192 ++++++++ drivers/hwtracing/coresight/coresight.c | 4 + include/linux/coresight.h | 23 + 8 files changed, 833 insertions(+) create mode 100644 drivers/hwtracing/coresight/coresight-cti-platform.c create mode 100644 drivers/hwtracing/coresight/coresight-cti-sysfs.c create mode 100644 drivers/hwtracing/coresight/coresight-cti.c create mode 100644 drivers/hwtracing/coresight/coresight-cti.h
diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig index 14638db4991d..98c525848662 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -109,4 +109,16 @@ config CORESIGHT_CPU_DEBUG properly, please refer Documentation/trace/coresight-cpu-debug.txt for detailed description and the example for usage.
+config CORESIGHT_CTI + bool "CoreSight Cross Trigger Interface (CTI) driver" + depends on ARM || ARM64 + help + This driver provides support for CoreSight CTI and CTM components. + These provide hardware triggering events between CoreSight trace + source and sink components. These can be used to halt trace or + inject events into the trace stream. CTI also provides a software + control to trigger the same halt events. This can provide fast trace + halt compared to disabling sources and sinks normally in driver + software. + endif diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 3c0ac421e211..43d563705e98 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -17,3 +17,7 @@ obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o \ obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o obj-$(CONFIG_CORESIGHT_CPU_DEBUG) += coresight-cpu-debug.o obj-$(CONFIG_CORESIGHT_CATU) += coresight-catu.o +obj-$(CONFIG_CORESIGHT_CTI) += coresight-cti.o \ + coresight-cti-platform.o \ + coresight-cti-sysfs.o + diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c new file mode 100644 index 000000000000..eb4f8a835c10 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/of.h> + +#include "coresight-cti.h" + +#ifdef CONFIG_OF +/* get the hardware configuration & connection data. */ +int of_cti_get_hw_data(struct device *dev, + struct device_node *np, + struct cti_drvdata *drvdata) +{ + int rc = 0; + struct cti_device *cti_dev = &drvdata->ctidev; + + /* if no connections, just add a single default based on max IN-OUT */ + if (cti_dev->nr_trig_con == 0) + rc = cti_add_default_connection(dev, drvdata); + return rc; +} + +/* + * Platform data for the CTI does not have the same connection info + * as the trace path components. Implement specific function to + * avoid warnings of missing connections. + */ +int of_get_coresight_cti_platform_data(struct device *dev, + struct coresight_platform_data *pdata) +{ + int ret = 0; + struct device_node *node = dev->of_node; + struct cti_drvdata *drvdata = dev_get_drvdata(dev); + + /* get some CTI specifics */ + ret = of_cti_get_hw_data(dev, node, drvdata); + + return ret; +} +#else +inline int +of_get_coresight_cti_platform_data(struct device *dev, + struct coresight_platform_data *pdata) +{ + return -ENOENT; +} + +#endif + +struct coresight_platform_data * +coresight_cti_get_platform_data(struct device *dev) +{ + int ret = -ENOENT; + struct coresight_platform_data *pdata = NULL; + struct fwnode_handle *fwnode = dev_fwnode(dev); + + if (IS_ERR_OR_NULL(fwnode)) + goto error; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + ret = -ENOMEM; + goto error; + } + + if (is_of_node(fwnode)) + ret = of_get_coresight_cti_platform_data(dev, pdata); + + if (!ret) + return pdata; +error: + return ERR_PTR(ret); +} diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c new file mode 100644 index 000000000000..a832b8c6b866 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 Linaro Limited, All rights reserved. + * Author: Mike Leach mike.leach@linaro.org + */ + +#include <linux/coresight.h> + +#include "coresight-cti.h" + +/* basic attributes */ +static ssize_t enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int enable_req; + bool enabled, powered; + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + + enable_req = atomic_read(&drvdata->config.enable_req_count); + spin_lock(&drvdata->spinlock); + powered = drvdata->config.hw_powered; + enabled = drvdata->config.hw_enabled; + spin_unlock(&drvdata->spinlock); + + if (powered) { + size = scnprintf(buf, PAGE_SIZE, "cti %s; powered;\n", + enabled ? "enabled" : "disabled"); + } else { + size = scnprintf(buf, PAGE_SIZE, "cti %s; unpowered;\n", + enable_req ? "enable req" : "disabled"); + } + return size; +} + +static ssize_t enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int ret = 0; + unsigned long val; + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + + ret = kstrtoul(buf, 0, &val); + if (ret) + return ret; + + if (val) + ret = cti_enable(drvdata->csdev); + else + ret = cti_disable(drvdata->csdev); + if (ret) + return ret; + return size; +} +static DEVICE_ATTR_RW(enable); + +/* attribute and group sysfs tables. */ +static struct attribute *coresight_cti_attrs[] = { + &dev_attr_enable.attr, + NULL, +}; + +static const struct attribute_group coresight_cti_group = { + .attrs = coresight_cti_attrs, +}; + +const struct attribute_group *coresight_cti_groups[] = { + &coresight_cti_group, + NULL, +}; diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c new file mode 100644 index 000000000000..b56d9a02c4b4 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -0,0 +1,451 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 Linaro Limited, All rights reserved. + * Author: Mike Leach mike.leach@linaro.org + */ + +#include "coresight-cti.h" + +/** + * CTI devices can be associated with a PE, or be connected to CoreSight + * hardware. We have a list of all CTIs irrespective of CPU bound or + * otherwise. + * + * We assume that the non-CPU CTIs are always powered as we do with sinks etc. + * + * We leave the client to figure out if all the CTIs are interconnected with + * the same CTM, in general this is the case but does not always have to be. + */ + +/* net of CTI devices connected via CTM */ +LIST_HEAD(ect_net); + +/* protect the list */ +static DEFINE_MUTEX(ect_mutex); + +#define csdev_to_cti_drvdata(csdev) \ + dev_get_drvdata(csdev->dev.parent) + +/* + * CTI naming. CTI bound to cores will have the name cti_cpu<N> where + * N is the CPU ID. System CTIs will have the name cti_sys<I> where I + * is an index allocated by order of discovery. + * + * CTI device name list - for CTI not bound to cores. + */ +DEFINE_CORESIGHT_DEVLIST(cti_sys_devs, "cti_sys"); + +/* write set of regs to hardware - call with spinlock claimed */ +static void cti_write_all_hw_regs(struct cti_drvdata *drvdata) +{ + struct cti_config *config = &drvdata->config; + int i; + + CS_UNLOCK(drvdata->base); + + /* disable CTI before writing registers */ + writel_relaxed(0, drvdata->base + CTICONTROL); + + /* write the CTI trigger registers */ + for (i = 0; i < config->nr_trig_max; i++) { + writel_relaxed(config->ctiinen[i], drvdata->base + CTIINEN(i)); + writel_relaxed(config->ctiouten[i], + drvdata->base + CTIOUTEN(i)); + } + + /* other regs */ + writel_relaxed(config->ctigate, drvdata->base + CTIGATE); + writel_relaxed(config->asicctl, drvdata->base + ASICCTL); + writel_relaxed(config->ctiappset, drvdata->base + CTIAPPSET); + + /* re-enable CTI */ + writel_relaxed(1, drvdata->base + CTICONTROL); + + CS_LOCK(drvdata->base); +} + +static void cti_enable_hw_smp_call(void *info) +{ + struct cti_drvdata *drvdata = info; + + cti_write_all_hw_regs(drvdata); +} + +/* write regs to hardware and enable */ +static int cti_enable_hw(struct cti_drvdata *drvdata, bool update_refcount) +{ + struct cti_config *config = &drvdata->config; + struct device *dev = &drvdata->csdev->dev; + int rc = 0; + + pm_runtime_get_sync(dev->parent); + spin_lock(&drvdata->spinlock); + + /* no need to do anything if enabled or unpowered*/ + if (config->hw_enabled || !config->hw_powered) + goto cti_state_unchanged; + + /* claim the device */ + rc = coresight_claim_device(drvdata->base); + if (rc) + goto cti_err_not_enabled; + + if (drvdata->ctidev.cpu >= 0) { + rc = smp_call_function_single(drvdata->ctidev.cpu, + cti_enable_hw_smp_call, + drvdata, 1); + if (rc) + goto cti_err_not_enabled; + } else + cti_write_all_hw_regs(drvdata); + + config->hw_enabled = true; + if (update_refcount) + atomic_inc(&drvdata->config.enable_req_count); + spin_unlock(&drvdata->spinlock); + return rc; + +cti_state_unchanged: + if (update_refcount) + atomic_inc(&drvdata->config.enable_req_count); + + /* cannot enable due to error */ +cti_err_not_enabled: + spin_unlock(&drvdata->spinlock); + pm_runtime_put(dev->parent); + return rc; +} + +/* disable hardware */ +static int cti_disable_hw(struct cti_drvdata *drvdata, bool update_refcount) +{ + struct cti_config *config = &drvdata->config; + struct device *dev = &drvdata->csdev->dev; + + spin_lock(&drvdata->spinlock); + + /* check refcount - disable on 0 */ + if (update_refcount && + (atomic_dec_return(&drvdata->config.enable_req_count) > 0)) + goto cti_not_disabled; + + /* no need to do anything if disabled or cpu unpowered */ + if (!config->hw_enabled || !config->hw_powered) + goto cti_not_disabled; + + CS_UNLOCK(drvdata->base); + + /* disable CTI */ + writel_relaxed(0, drvdata->base + CTICONTROL); + config->hw_enabled = false; + + coresight_disclaim_device_unlocked(drvdata->base); + CS_LOCK(drvdata->base); + spin_unlock(&drvdata->spinlock); + pm_runtime_put(dev); + return 0; + + /* not disabled this call */ +cti_not_disabled: + spin_unlock(&drvdata->spinlock); + return 0; +} + +/* + * Look at the HW DEVID register for some of the HW settings. + * DEVID[15:8] - max number of in / out triggers. + */ +#define CTI_DEVID_MAXTRIGS(devid_val) (int)((devid_val & 0xFF00) >> 8) + +/* DEVID[19:16] - number of CTM channels */ +#define CTI_DEVID_CTMCHANNELS(devid_val) (int)((devid_val & 0xF0000) >> 16) + +static void cti_set_default_config(struct device *dev, + struct cti_drvdata *drvdata) +{ + struct cti_config *config = &drvdata->config; + u32 devid; + + devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID); + config->nr_trig_max = CTI_DEVID_MAXTRIGS(devid); + + /* + * no current hardware should exceed this, but protect the driver + * in case of fault / out of spec hw + */ + if (config->nr_trig_max > CTIINOUTEN_MAX) { + dev_warn_once(dev, + "Limiting HW MaxTrig value(%d) to driver max(%d)\n", + config->nr_trig_max, CTIINOUTEN_MAX); + config->nr_trig_max = CTIINOUTEN_MAX; + } + + config->nr_ctm_channels = CTI_DEVID_CTMCHANNELS(devid); + + /* Most regs default to 0 as zalloc'ed except...*/ + config->trig_filter_enable = true; + config->ctigate = GENMASK(config->nr_ctm_channels - 1, 0); + atomic_set(&config->enable_req_count, 0); +} + +/* + * Add a connection entry to the list of connections for this + * CTI device. + */ +int cti_add_connection_entry(struct device *dev, struct cti_drvdata *drvdata, + struct cti_trig_con *tc, + struct coresight_device *csdev, + const char *assoc_dev_name) +{ + struct cti_device *cti_dev = &drvdata->ctidev; + + tc->con_dev = csdev; + /* + * Prefer actual associated CS device dev name to supplied value - + * which is likely to be node name / other conn name. + */ + if (csdev) + tc->con_dev_name = devm_kstrdup(dev, + dev_name(&csdev->dev), + GFP_KERNEL); + else if (assoc_dev_name != NULL) + tc->con_dev_name = devm_kstrdup(dev, + assoc_dev_name, GFP_KERNEL); + list_add_tail(&tc->node, &cti_dev->trig_cons); + cti_dev->nr_trig_con++; + + /* add connection usage bit info to overall info */ + drvdata->config.trig_in_use |= tc->con_in->used_mask; + drvdata->config.trig_out_use |= tc->con_out->used_mask; + + return 0; +} + +/* create a trigger connection with appropriately sized signal groups */ +struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs, + int out_sigs) +{ + struct cti_trig_con *tc = NULL; + struct cti_trig_grp *in = NULL, *out = NULL; + + tc = devm_kzalloc(dev, sizeof(struct cti_trig_con), GFP_KERNEL); + if (!tc) + return tc; + + in = devm_kzalloc(dev, + offsetof(struct cti_trig_grp, sig_types[in_sigs]), + GFP_KERNEL); + if (!in) + return NULL; + + out = devm_kzalloc(dev, + offsetof(struct cti_trig_grp, sig_types[out_sigs]), + GFP_KERNEL); + if (!out) + return NULL; + + tc->con_in = in; + tc->con_out = out; + tc->con_in->nr_sigs = in_sigs; + tc->con_out->nr_sigs = out_sigs; + return tc; +} + +/* + * Add a default connection if nothing else is specified. + * single connection based on max in/out info, no assoc device + */ +int cti_add_default_connection(struct device *dev, struct cti_drvdata *drvdata) +{ + int ret = 0; + int n_trigs = drvdata->config.nr_trig_max; + u32 n_trig_mask = GENMASK(n_trigs - 1, 0); + struct cti_trig_con *tc = NULL; + + /* + * Assume max trigs for in and out, + * all used, default sig types allocated + */ + tc = cti_allocate_trig_con(dev, n_trigs, n_trigs); + if (!tc) + return -ENOMEM; + + tc->con_in->used_mask = n_trig_mask; + tc->con_out->used_mask = n_trig_mask; + ret = cti_add_connection_entry(dev, drvdata, tc, NULL, "default"); + return ret; +} + +/** cti ect operations **/ +int cti_enable(struct coresight_device *csdev) +{ + struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev); + + /* enable hardware with refcount */ + return cti_enable_hw(drvdata, true); +} + +int cti_disable(struct coresight_device *csdev) +{ + struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev); + + /* disable hardware with refcount */ + return cti_disable_hw(drvdata, true); +} + +const struct coresight_ops_ect cti_ops_ect = { + .enable = cti_enable, + .disable = cti_disable, +}; + +const struct coresight_ops cti_ops = { + .ect_ops = &cti_ops_ect, +}; + +/* + * Free up CTI specific resources + * called by dev->release, need to call down to underlying csdev release. + */ +static void cti_device_release(struct device *dev) +{ + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cti_drvdata *ect_item, *ect_tmp; + + mutex_lock(&ect_mutex); + + /* remove from the list */ + list_for_each_entry_safe(ect_item, ect_tmp, &ect_net, node) { + if (ect_item == drvdata) { + list_del(&ect_item->node); + goto ect_list_item_removed; + } + } +ect_list_item_removed: + mutex_unlock(&ect_mutex); + + if (drvdata->csdev_release) + drvdata->csdev_release(dev); +} + +static int cti_probe(struct amba_device *adev, const struct amba_id *id) +{ + int ret = 0; + void __iomem *base; + struct device *dev = &adev->dev; + struct cti_drvdata *drvdata = NULL; + struct coresight_desc cti_desc; + struct coresight_platform_data *pdata = NULL; + struct resource *res = &adev->res; + + /* driver data*/ + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) { + ret = -ENOMEM; + dev_info(dev, "%s, mem err\n", __func__); + goto err_out; + } + + /* Validity for the resource is already checked by the AMBA core */ + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) { + ret = PTR_ERR(base); + dev_info(dev, "%s, remap err\n", __func__); + goto err_out; + } + drvdata->base = base; + + dev_set_drvdata(dev, drvdata); + + /* default CTI device info */ + drvdata->ctidev.cpu = -1; + drvdata->ctidev.nr_trig_con = 0; + drvdata->ctidev.ctm_id = 0; + INIT_LIST_HEAD(&drvdata->ctidev.trig_cons); + + spin_lock_init(&drvdata->spinlock); + + /* initialise CTI driver config values */ + cti_set_default_config(dev, drvdata); + + /* Parse the .dts for connections and signals */ + pdata = coresight_cti_get_platform_data(dev); + if (IS_ERR(pdata)) { + dev_info(dev, "coresight_cti_get_platform_data err\n"); + ret = PTR_ERR(pdata); + goto err_out; + } + + /* default to powered - could change on PM notifications */ + drvdata->config.hw_powered = true; + + /* set up device name - will depend if cpu bound or otherwise */ + if (drvdata->ctidev.cpu >= 0) + cti_desc.name = devm_kasprintf(dev, GFP_KERNEL, "cti_cpu%d", + drvdata->ctidev.cpu); + else + cti_desc.name = coresight_alloc_device_name(&cti_sys_devs, dev); + if (!cti_desc.name) { + ret = -ENOMEM; + goto err_out; + } + + /* set up coresight component description */ + cti_desc.pdata = pdata; + cti_desc.type = CORESIGHT_DEV_TYPE_ECT; + cti_desc.subtype.ect_subtype = CORESIGHT_DEV_SUBTYPE_ECT_CTI; + cti_desc.ops = &cti_ops; + cti_desc.groups = coresight_cti_groups; + cti_desc.dev = dev; + drvdata->csdev = coresight_register(&cti_desc); + if (IS_ERR(drvdata->csdev)) { + ret = PTR_ERR(drvdata->csdev); + goto err_out; + } + + /* add to list of CTI devices */ + mutex_lock(&ect_mutex); + list_add(&drvdata->node, &ect_net); + mutex_unlock(&ect_mutex); + + /* set up release chain */ + drvdata->csdev_release = drvdata->csdev->dev.release; + drvdata->csdev->dev.release = cti_device_release; + + /* all done - dec pm refcount */ + pm_runtime_put(&adev->dev); + dev_info(dev, "%s: CTI initialized\n", cti_desc.name); + return 0; + +err_out: + return ret; +} + +static struct amba_cs_uci_id uci_id_cti[] = { + { + /* CTI UCI data */ + .devarch = 0x47701a14, /* CTI v2 */ + .devarch_mask = 0xfff0ffff, + .devtype = 0x00000014, /* maj(0x4-debug) min(0x1-ECT) */ + } +}; + +static const struct amba_id cti_ids[] = { + CS_AMBA_ID(0x000bb906), /* Coresight CTI (SoC 400), C-A72, C-A57 */ + CS_AMBA_ID(0x000bb922), /* CTI - C-A8 */ + CS_AMBA_ID(0x000bb9a8), /* CTI - C-A53 */ + CS_AMBA_ID(0x000bb9aa), /* CTI - C-A73 */ + CS_AMBA_UCI_ID(0x000bb9da, uci_id_cti), /* CTI - C-A35 */ + CS_AMBA_UCI_ID(0x000bb9ed, uci_id_cti), /* Coresight CTI (SoC 600) */ + { 0, 0}, +}; + +static struct amba_driver cti_driver = { + .drv = { + .name = "coresight-cti", + .owner = THIS_MODULE, + .suppress_bind_attrs = true, + }, + .probe = cti_probe, + .id_table = cti_ids, +}; +builtin_amba_driver(cti_driver); diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h new file mode 100644 index 000000000000..717035a9aa72 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -0,0 +1,192 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018 Linaro Limited, All rights reserved. + * Author: Mike Leach mike.leach@linaro.org + */ + +#ifndef _CORESIGHT_CORESIGHT_CTI_H +#define _CORESIGHT_CORESIGHT_CTI_H + +#include <asm/local.h> +#include <linux/spinlock.h> +#include "coresight-priv.h" + +/* + * Device registers + * 0x000 - 0x144: CTI programming and status + * 0xEDC - 0xEF8: CTI integration test. + * 0xF00 - 0xFFC: Coresight management registers. + */ +/* CTI programming registers */ +#define CTICONTROL 0x000 +#define CTIINTACK 0x010 +#define CTIAPPSET 0x014 +#define CTIAPPCLEAR 0x018 +#define CTIAPPPULSE 0x01C +#define CTIINEN(n) (0x020 + (4 * n)) +#define CTIOUTEN(n) (0x0A0 + (4 * n)) +#define CTITRIGINSTATUS 0x130 +#define CTITRIGOUTSTATUS 0x134 +#define CTICHINSTATUS 0x138 +#define CTICHOUTSTATUS 0x13C +#define CTIGATE 0x140 +#define ASICCTL 0x144 +/* Integration test registers */ +#define ITCHINACK 0xEDC /* WO CTI CSSoc 400 only*/ +#define ITTRIGINACK 0xEE0 /* WO CTI CSSoc 400 only*/ +#define ITCHOUT 0xEE4 /* WO RW-600 */ +#define ITTRIGOUT 0xEE8 /* WO RW-600 */ +#define ITCHOUTACK 0xEEC /* RO CTI CSSoc 400 only*/ +#define ITTRIGOUTACK 0xEF0 /* RO CTI CSSoc 400 only*/ +#define ITCHIN 0xEF4 /* RO */ +#define ITTRIGIN 0xEF8 /* RO */ +/* management registers */ +#define CTIDEVAFF0 0xFA8 +#define CTIDEVAFF1 0xFAC + +/* + * CTI CSSoc 600 has a max of 32 trigger signals per direction. + * CTI CSSoc 400 has 8 IO triggers - other CTIs can be impl def. + * Max of in and out defined in the DEVID register. + * - pick up actual number used from .dts parameters if present. + */ +#define CTIINOUTEN_MAX 32 + +/** + * Group of related trigger signals + * + * @nr_sigs: number of signals in the group. + * @used_mask: bitmask representing the signal indexes in the group. + * @sig_types: array of types for the signals, length nr_sigs. + */ +struct cti_trig_grp { + int nr_sigs; + u32 used_mask; + int sig_types[0]; +}; + +/** + * Trigger connection - connection between a CTI and other (coresight) device + * lists input and output trigger signals for the device + * + * @con_in: connected CTIIN signals for the device. + * @con_out: connected CTIOUT signals for the device. + * @con_dev: coresight device connected to the CTI, NULL if not CS device + * @con_dev_name: name of connected device (CS or CPU) + * @node: entry node in list of connections. + */ +struct cti_trig_con { + struct cti_trig_grp *con_in; + struct cti_trig_grp *con_out; + struct coresight_device *con_dev; + char *con_dev_name; + struct list_head node; +}; + +/** + * struct cti_device - description of CTI device properties. + * + * @nt_trig_con: Number of external devices connected to this device. + * @ctm_id: which CTM this device is connected to (by default it is + * assumed there is a single CTM per SoC, ID 0). + * @trig_cons: list of connections to this device. + * @cpu: CPU ID if associated with CPU, -1 otherwise. + */ +struct cti_device { + int nr_trig_con; + u32 ctm_id; + struct list_head trig_cons; + int cpu; +}; + +/** + * struct cti_config - configuration of the CTI device hardware + * + * Hardware description from RO ID regs + * @nr_trig_max: Max number of trigger signals implemented on device. + * (max of trig_in or trig_out) + * @nr_ctm_channels: number of available CTM channels + * + * Cti enable control + * @enable_req_count: CTI is enabled alongside >=1 associated devices. + * @hw_enabled: true if hw is currently enabled. + * @hw_powered: true if associated cpu powered on, or no cpu. + * + * Registered triggers and filtering + * @trig_in_use: bitfield of in triggers registered as in use. + * @trig_out_use: bitfield of out triggers registered as in use. + * @trig_out_filter: bitfield of out triggers that are blocked if filter + * enabled. Typically this would be dbgreq / restart on a core CTI. + * @trig_filter_enable: 1 if filtering enabled. + * @xtrig_rchan_sel: channel selection for xtrigger connection show. + * + * Cti software programmable regs: + * @ctiappset: CTI Software application channel set. + * @ctiinout_sel: register selector for INEN and OUTEN regs. + * @ctiinen: enable input trigger to a channel. + * @ctiouten: enable output trigger from a channel. + * @ctigate: gate channel output from CTI to CTM. + * @asicctl: asic control register. + */ +struct cti_config { + /* hardware description */ + int nr_ctm_channels; + int nr_trig_max; + + /* cti enable control */ + atomic_t enable_req_count; + bool hw_enabled; + bool hw_powered; + + /* registered triggers and filtering */ + u32 trig_in_use; + u32 trig_out_use; + u32 trig_out_filter; + bool trig_filter_enable; + u8 xtrig_rchan_sel; + + /* cti cross trig programmable regs */ + u32 ctiappset; + u8 ctiinout_sel; + u32 ctiinen[CTIINOUTEN_MAX]; + u32 ctiouten[CTIINOUTEN_MAX]; + u32 ctigate; + u32 asicctl; +}; + +/** + * struct cti_drvdata - specifics for the CTI device + * @base: Memory mapped base address for this component.. + * @csdev: Standard CoreSight device information. + * @ctidev: Extra information needed by the CTI/CTM framework. + * @spinlock: Control data access to one at a time. + * @config: Configuration data for this CTI device. + * @node: List entry of this device in the list of CTI devices. + * @csdev_release: release function for underlying coresight_device. + */ +struct cti_drvdata { + void __iomem *base; + struct coresight_device *csdev; + struct cti_device ctidev; + spinlock_t spinlock; + struct cti_config config; + struct list_head node; + void (*csdev_release)(struct device *dev); +}; + +/* private cti driver fns & vars */ +extern const struct attribute_group *coresight_cti_groups[]; +int cti_add_default_connection(struct device *dev, + struct cti_drvdata *drvdata); +int cti_add_connection_entry(struct device *dev, struct cti_drvdata *drvdata, + struct cti_trig_con *tc, + struct coresight_device *csdev, + const char *assoc_dev_name); +struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs, + int out_sigs); +int cti_enable(struct coresight_device *csdev); +int cti_disable(struct coresight_device *csdev); +struct coresight_platform_data * +coresight_cti_get_platform_data(struct device *dev); + +#endif /* _CORESIGHT_CORESIGHT_CTI_H */ diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 6453c67a4d01..64ff810394f9 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -972,6 +972,9 @@ static struct device_type coresight_dev_type[] = { { .name = "helper", }, + { + .name = "ect", + }, };
static void coresight_device_release(struct device *dev) @@ -979,6 +982,7 @@ static void coresight_device_release(struct device *dev) struct coresight_device *csdev = to_coresight_device(dev);
fwnode_handle_put(csdev->dev.fwnode); + kfree(csdev->refcnt); kfree(csdev); } diff --git a/include/linux/coresight.h b/include/linux/coresight.h index a2b68823717b..2a23c3cdf8e4 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -41,6 +41,7 @@ enum coresight_dev_type { CORESIGHT_DEV_TYPE_LINKSINK, CORESIGHT_DEV_TYPE_SOURCE, CORESIGHT_DEV_TYPE_HELPER, + CORESIGHT_DEV_TYPE_ECT, };
enum coresight_dev_subtype_sink { @@ -68,6 +69,12 @@ enum coresight_dev_subtype_helper { CORESIGHT_DEV_SUBTYPE_HELPER_CATU, };
+/* Embedded Cross Trigger (ECT) sub-types */ +enum coresight_dev_subtype_ect { + CORESIGHT_DEV_SUBTYPE_ECT_NONE, + CORESIGHT_DEV_SUBTYPE_ECT_CTI, +}; + /** * union coresight_dev_subtype - further characterisation of a type * @sink_subtype: type of sink this component is, as defined @@ -78,6 +85,8 @@ enum coresight_dev_subtype_helper { * by @coresight_dev_subtype_source. * @helper_subtype: type of helper this component is, as defined * by @coresight_dev_subtype_helper. + * @ect_subtype: type of cross trigger this component is, as + * defined by @coresight_dev_subtype_ect */ union coresight_dev_subtype { /* We have some devices which acts as LINK and SINK */ @@ -87,6 +96,7 @@ union coresight_dev_subtype { }; enum coresight_dev_subtype_source source_subtype; enum coresight_dev_subtype_helper helper_subtype; + enum coresight_dev_subtype_ect ect_subtype; };
/** @@ -196,6 +206,7 @@ static struct coresight_dev_list (var) = { \ #define sink_ops(csdev) csdev->ops->sink_ops #define link_ops(csdev) csdev->ops->link_ops #define helper_ops(csdev) csdev->ops->helper_ops +#define ect_ops(csdev) csdev->ops->ect_ops
/** * struct coresight_ops_sink - basic operations for a sink @@ -262,11 +273,23 @@ struct coresight_ops_helper { int (*disable)(struct coresight_device *csdev, void *data); };
+/** + * struct coresight_ops_ect - Ops for an embedded cross trigger device + * + * @enable : Enable the device + * @disable : Disable the device + */ +struct coresight_ops_ect { + int (*enable)(struct coresight_device *csdev); + int (*disable)(struct coresight_device *csdev); +}; + struct coresight_ops { const struct coresight_ops_sink *sink_ops; const struct coresight_ops_link *link_ops; const struct coresight_ops_source *source_ops; const struct coresight_ops_helper *helper_ops; + const struct coresight_ops_ect *ect_ops; };
#ifdef CONFIG_CORESIGHT
Hi Mike,
On Mon, Aug 19, 2019 at 10:13:47PM +0100, Mike Leach wrote:
Since this is big patch, trimed the code significantly when review; hope this will not cause difficulty for reading my comments.
When I applied this patch, git complained as below:
$ git am /tmp/cs_cti_patch_v4/01.patch Applying: coresight: cti: Initial CoreSight CTI Driver .git/rebase-apply/patch:48: new blank line at EOF. + warning: 1 line adds whitespace errors.
[...]
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c new file mode 100644 index 000000000000..eb4f8a835c10 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2019, The Linux Foundation. All rights reserved.
Here should be "Linaro Limited"?
[...]
diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c new file mode 100644 index 000000000000..b56d9a02c4b4 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -0,0 +1,451 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2019 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include "coresight-cti.h"
+/**
- CTI devices can be associated with a PE, or be connected to CoreSight
- hardware. We have a list of all CTIs irrespective of CPU bound or
- otherwise.
- We assume that the non-CPU CTIs are always powered as we do with sinks etc.
- We leave the client to figure out if all the CTIs are interconnected with
- the same CTM, in general this is the case but does not always have to be.
- */
+/* net of CTI devices connected via CTM */ +LIST_HEAD(ect_net);
+/* protect the list */ +static DEFINE_MUTEX(ect_mutex);
+#define csdev_to_cti_drvdata(csdev) \
- dev_get_drvdata(csdev->dev.parent)
+/*
- CTI naming. CTI bound to cores will have the name cti_cpu<N> where
- N is the CPU ID. System CTIs will have the name cti_sys<I> where I
- is an index allocated by order of discovery.
- CTI device name list - for CTI not bound to cores.
- */
+DEFINE_CORESIGHT_DEVLIST(cti_sys_devs, "cti_sys");
+/* write set of regs to hardware - call with spinlock claimed */ +static void cti_write_all_hw_regs(struct cti_drvdata *drvdata) +{
- struct cti_config *config = &drvdata->config;
- int i;
- CS_UNLOCK(drvdata->base);
- /* disable CTI before writing registers */
- writel_relaxed(0, drvdata->base + CTICONTROL);
- /* write the CTI trigger registers */
- for (i = 0; i < config->nr_trig_max; i++) {
writel_relaxed(config->ctiinen[i], drvdata->base + CTIINEN(i));
writel_relaxed(config->ctiouten[i],
drvdata->base + CTIOUTEN(i));
- }
- /* other regs */
- writel_relaxed(config->ctigate, drvdata->base + CTIGATE);
- writel_relaxed(config->asicctl, drvdata->base + ASICCTL);
- writel_relaxed(config->ctiappset, drvdata->base + CTIAPPSET);
- /* re-enable CTI */
- writel_relaxed(1, drvdata->base + CTICONTROL);
Just curious, usually for switching on/off for module, it's more safe to use writel() rather than writel_relax(), since writel() has a memory barrier prior to access to CTICONTROL register, thus this can give chance to write other configurations to the endpoint before really enable/disable the module.
If you think writel_relaxed() is safe enough, sorry for noise.
- CS_LOCK(drvdata->base);
+}
[...]
+/* disable hardware */ +static int cti_disable_hw(struct cti_drvdata *drvdata, bool update_refcount)
I read the comments in the patch set v3, Suzuki has mentioned "update_refcount" is not really used. In this patch set, "update_refcount" is only set as 'true' when call cti_disable_hw().
Just bring up if you are missing this or you deliberately keep this parameter and will be used later (e.g. for PM notifier?).
+{
- struct cti_config *config = &drvdata->config;
- struct device *dev = &drvdata->csdev->dev;
- spin_lock(&drvdata->spinlock);
- /* check refcount - disable on 0 */
- if (update_refcount &&
(atomic_dec_return(&drvdata->config.enable_req_count) > 0))
goto cti_not_disabled;
- /* no need to do anything if disabled or cpu unpowered */
- if (!config->hw_enabled || !config->hw_powered)
goto cti_not_disabled;
- CS_UNLOCK(drvdata->base);
- /* disable CTI */
- writel_relaxed(0, drvdata->base + CTICONTROL);
- config->hw_enabled = false;
- coresight_disclaim_device_unlocked(drvdata->base);
- CS_LOCK(drvdata->base);
- spin_unlock(&drvdata->spinlock);
- pm_runtime_put(dev);
- return 0;
- /* not disabled this call */
+cti_not_disabled:
- spin_unlock(&drvdata->spinlock);
- return 0;
+}
[...]
diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 6453c67a4d01..64ff810394f9 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -972,6 +972,9 @@ static struct device_type coresight_dev_type[] = { { .name = "helper", },
- {
.name = "ect",
- },
}; static void coresight_device_release(struct device *dev) @@ -979,6 +982,7 @@ static void coresight_device_release(struct device *dev) struct coresight_device *csdev = to_coresight_device(dev); fwnode_handle_put(csdev->dev.fwnode);
Redundant new line?
kfree(csdev->refcnt); kfree(csdev); }
[...]
Thanks, Leo Yan
Hey Mike,
On Mon, Aug 19, 2019 at 10:13:47PM +0100, Mike Leach wrote:
This introduces a baseline CTI driver and associated configuration files.
Uses the platform agnostic naming standard for CoreSight devices, along with a generic platform probing method that currently supports device tree descriptions, but allows for the ACPI bindings to be added once these have been defined for the CTI devices.
Driver will probe for the device on the AMBA bus, and load the CTI driver on CoreSight ID match to CTI IDs in tables.
Initial sysfs support for enable / disable provided.
Default CTI interconnection data is generated based on hardware register signal counts, with no additional connection information.
This is really coming along well - please see minor comments below.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Kconfig | 12 + drivers/hwtracing/coresight/Makefile | 4 + .../coresight/coresight-cti-platform.c | 75 +++ .../hwtracing/coresight/coresight-cti-sysfs.c | 72 +++ drivers/hwtracing/coresight/coresight-cti.c | 451 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.h | 192 ++++++++ drivers/hwtracing/coresight/coresight.c | 4 + include/linux/coresight.h | 23 + 8 files changed, 833 insertions(+) create mode 100644 drivers/hwtracing/coresight/coresight-cti-platform.c create mode 100644 drivers/hwtracing/coresight/coresight-cti-sysfs.c create mode 100644 drivers/hwtracing/coresight/coresight-cti.c create mode 100644 drivers/hwtracing/coresight/coresight-cti.h
diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig index 14638db4991d..98c525848662 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -109,4 +109,16 @@ config CORESIGHT_CPU_DEBUG properly, please refer Documentation/trace/coresight-cpu-debug.txt for detailed description and the example for usage. +config CORESIGHT_CTI
- bool "CoreSight Cross Trigger Interface (CTI) driver"
- depends on ARM || ARM64
- help
This driver provides support for CoreSight CTI and CTM components.
These provide hardware triggering events between CoreSight trace
source and sink components. These can be used to halt trace or
inject events into the trace stream. CTI also provides a software
control to trigger the same halt events. This can provide fast trace
halt compared to disabling sources and sinks normally in driver
software.
endif diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 3c0ac421e211..43d563705e98 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -17,3 +17,7 @@ obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o \ obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o obj-$(CONFIG_CORESIGHT_CPU_DEBUG) += coresight-cpu-debug.o obj-$(CONFIG_CORESIGHT_CATU) += coresight-catu.o +obj-$(CONFIG_CORESIGHT_CTI) += coresight-cti.o \
coresight-cti-platform.o \
coresight-cti-sysfs.o
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c new file mode 100644 index 000000000000..eb4f8a835c10 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2019, The Linux Foundation. All rights reserved.
Leo already commented on the Linux Foundation part.
- */
+#include <linux/of.h>
+#include "coresight-cti.h"
+#ifdef CONFIG_OF +/* get the hardware configuration & connection data. */ +int of_cti_get_hw_data(struct device *dev,
struct device_node *np,
struct cti_drvdata *drvdata)
+{
- int rc = 0;
- struct cti_device *cti_dev = &drvdata->ctidev;
- /* if no connections, just add a single default based on max IN-OUT */
- if (cti_dev->nr_trig_con == 0)
rc = cti_add_default_connection(dev, drvdata);
- return rc;
+}
+/*
- Platform data for the CTI does not have the same connection info
- as the trace path components. Implement specific function to
- avoid warnings of missing connections.
- */
+int of_get_coresight_cti_platform_data(struct device *dev,
struct coresight_platform_data *pdata)
+{
- int ret = 0;
- struct device_node *node = dev->of_node;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev);
- /* get some CTI specifics */
- ret = of_cti_get_hw_data(dev, node, drvdata);
- return ret;
+} +#else +inline int +of_get_coresight_cti_platform_data(struct device *dev,
struct coresight_platform_data *pdata)
+{
- return -ENOENT;
+}
+#endif
+struct coresight_platform_data * +coresight_cti_get_platform_data(struct device *dev) +{
- int ret = -ENOENT;
- struct coresight_platform_data *pdata = NULL;
- struct fwnode_handle *fwnode = dev_fwnode(dev);
- if (IS_ERR_OR_NULL(fwnode))
goto error;
- pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
ret = -ENOMEM;
goto error;
- }
- if (is_of_node(fwnode))
ret = of_get_coresight_cti_platform_data(dev, pdata);
- if (!ret)
return pdata;
+error:
- return ERR_PTR(ret);
+} diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c new file mode 100644 index 000000000000..a832b8c6b866 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2019 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <linux/coresight.h>
+#include "coresight-cti.h"
+/* basic attributes */ +static ssize_t enable_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- int enable_req;
- bool enabled, powered;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- ssize_t size = 0;
- enable_req = atomic_read(&drvdata->config.enable_req_count);
- spin_lock(&drvdata->spinlock);
- powered = drvdata->config.hw_powered;
- enabled = drvdata->config.hw_enabled;
- spin_unlock(&drvdata->spinlock);
- if (powered) {
size = scnprintf(buf, PAGE_SIZE, "cti %s; powered;\n",
enabled ? "enabled" : "disabled");
- } else {
size = scnprintf(buf, PAGE_SIZE, "cti %s; unpowered;\n",
enable_req ? "enable req" : "disabled");
- }
- return size;
+}
+static ssize_t enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- int ret = 0;
- unsigned long val;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- ret = kstrtoul(buf, 0, &val);
- if (ret)
return ret;
- if (val)
ret = cti_enable(drvdata->csdev);
- else
ret = cti_disable(drvdata->csdev);
- if (ret)
return ret;
- return size;
+} +static DEVICE_ATTR_RW(enable);
+/* attribute and group sysfs tables. */ +static struct attribute *coresight_cti_attrs[] = {
- &dev_attr_enable.attr,
- NULL,
+};
+static const struct attribute_group coresight_cti_group = {
- .attrs = coresight_cti_attrs,
+};
+const struct attribute_group *coresight_cti_groups[] = {
- &coresight_cti_group,
- NULL,
+}; diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c new file mode 100644 index 000000000000..b56d9a02c4b4 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -0,0 +1,451 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2019 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
This is 2019 but in coresight-cti.c it is 2018.
- */
+#include "coresight-cti.h"
+/**
- CTI devices can be associated with a PE, or be connected to CoreSight
- hardware. We have a list of all CTIs irrespective of CPU bound or
- otherwise.
- We assume that the non-CPU CTIs are always powered as we do with sinks etc.
- We leave the client to figure out if all the CTIs are interconnected with
- the same CTM, in general this is the case but does not always have to be.
- */
+/* net of CTI devices connected via CTM */ +LIST_HEAD(ect_net);
+/* protect the list */ +static DEFINE_MUTEX(ect_mutex);
+#define csdev_to_cti_drvdata(csdev) \
- dev_get_drvdata(csdev->dev.parent)
+/*
- CTI naming. CTI bound to cores will have the name cti_cpu<N> where
- N is the CPU ID. System CTIs will have the name cti_sys<I> where I
- is an index allocated by order of discovery.
- CTI device name list - for CTI not bound to cores.
- */
+DEFINE_CORESIGHT_DEVLIST(cti_sys_devs, "cti_sys");
+/* write set of regs to hardware - call with spinlock claimed */ +static void cti_write_all_hw_regs(struct cti_drvdata *drvdata) +{
- struct cti_config *config = &drvdata->config;
- int i;
- CS_UNLOCK(drvdata->base);
- /* disable CTI before writing registers */
- writel_relaxed(0, drvdata->base + CTICONTROL);
- /* write the CTI trigger registers */
- for (i = 0; i < config->nr_trig_max; i++) {
writel_relaxed(config->ctiinen[i], drvdata->base + CTIINEN(i));
writel_relaxed(config->ctiouten[i],
drvdata->base + CTIOUTEN(i));
- }
- /* other regs */
- writel_relaxed(config->ctigate, drvdata->base + CTIGATE);
- writel_relaxed(config->asicctl, drvdata->base + ASICCTL);
- writel_relaxed(config->ctiappset, drvdata->base + CTIAPPSET);
- /* re-enable CTI */
- writel_relaxed(1, drvdata->base + CTICONTROL);
- CS_LOCK(drvdata->base);
+}
+static void cti_enable_hw_smp_call(void *info) +{
- struct cti_drvdata *drvdata = info;
- cti_write_all_hw_regs(drvdata);
+}
+/* write regs to hardware and enable */ +static int cti_enable_hw(struct cti_drvdata *drvdata, bool update_refcount) +{
Just like Leo and Suzuki, I am perplexed about the @update_refcount part. Even after applying all the patches function cti_enable/disable_hw() are always called the same way.
- struct cti_config *config = &drvdata->config;
- struct device *dev = &drvdata->csdev->dev;
- int rc = 0;
- pm_runtime_get_sync(dev->parent);
- spin_lock(&drvdata->spinlock);
- /* no need to do anything if enabled or unpowered*/
- if (config->hw_enabled || !config->hw_powered)
goto cti_state_unchanged;
- /* claim the device */
- rc = coresight_claim_device(drvdata->base);
- if (rc)
goto cti_err_not_enabled;
- if (drvdata->ctidev.cpu >= 0) {
rc = smp_call_function_single(drvdata->ctidev.cpu,
cti_enable_hw_smp_call,
drvdata, 1);
Alignment problem - the second and third line have to be aligned with drvdata.
if (rc)
goto cti_err_not_enabled;
- } else
cti_write_all_hw_regs(drvdata);
Add curly braces, normally checkpatch will catch those.
- config->hw_enabled = true;
- if (update_refcount)
atomic_inc(&drvdata->config.enable_req_count);
- spin_unlock(&drvdata->spinlock);
- return rc;
+cti_state_unchanged:
- if (update_refcount)
atomic_inc(&drvdata->config.enable_req_count);
- /* cannot enable due to error */
+cti_err_not_enabled:
- spin_unlock(&drvdata->spinlock);
- pm_runtime_put(dev->parent);
- return rc;
+}
+/* disable hardware */ +static int cti_disable_hw(struct cti_drvdata *drvdata, bool update_refcount) +{
- struct cti_config *config = &drvdata->config;
- struct device *dev = &drvdata->csdev->dev;
- spin_lock(&drvdata->spinlock);
- /* check refcount - disable on 0 */
- if (update_refcount &&
(atomic_dec_return(&drvdata->config.enable_req_count) > 0))
goto cti_not_disabled;
- /* no need to do anything if disabled or cpu unpowered */
- if (!config->hw_enabled || !config->hw_powered)
goto cti_not_disabled;
- CS_UNLOCK(drvdata->base);
- /* disable CTI */
- writel_relaxed(0, drvdata->base + CTICONTROL);
- config->hw_enabled = false;
- coresight_disclaim_device_unlocked(drvdata->base);
- CS_LOCK(drvdata->base);
- spin_unlock(&drvdata->spinlock);
- pm_runtime_put(dev);
- return 0;
- /* not disabled this call */
+cti_not_disabled:
- spin_unlock(&drvdata->spinlock);
- return 0;
+}
+/*
- Look at the HW DEVID register for some of the HW settings.
- DEVID[15:8] - max number of in / out triggers.
- */
+#define CTI_DEVID_MAXTRIGS(devid_val) (int)((devid_val & 0xFF00) >> 8)
+/* DEVID[19:16] - number of CTM channels */ +#define CTI_DEVID_CTMCHANNELS(devid_val) (int)((devid_val & 0xF0000) >> 16)
+static void cti_set_default_config(struct device *dev,
struct cti_drvdata *drvdata)
+{
- struct cti_config *config = &drvdata->config;
- u32 devid;
- devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID);
- config->nr_trig_max = CTI_DEVID_MAXTRIGS(devid);
- /*
* no current hardware should exceed this, but protect the driver
* in case of fault / out of spec hw
*/
- if (config->nr_trig_max > CTIINOUTEN_MAX) {
dev_warn_once(dev,
"Limiting HW MaxTrig value(%d) to driver max(%d)\n",
config->nr_trig_max, CTIINOUTEN_MAX);
config->nr_trig_max = CTIINOUTEN_MAX;
- }
- config->nr_ctm_channels = CTI_DEVID_CTMCHANNELS(devid);
- /* Most regs default to 0 as zalloc'ed except...*/
- config->trig_filter_enable = true;
- config->ctigate = GENMASK(config->nr_ctm_channels - 1, 0);
- atomic_set(&config->enable_req_count, 0);
+}
+/*
- Add a connection entry to the list of connections for this
- CTI device.
- */
+int cti_add_connection_entry(struct device *dev, struct cti_drvdata *drvdata,
struct cti_trig_con *tc,
struct coresight_device *csdev,
const char *assoc_dev_name)
+{
- struct cti_device *cti_dev = &drvdata->ctidev;
- tc->con_dev = csdev;
- /*
* Prefer actual associated CS device dev name to supplied value -
* which is likely to be node name / other conn name.
*/
- if (csdev)
tc->con_dev_name = devm_kstrdup(dev,
dev_name(&csdev->dev),
GFP_KERNEL);
- else if (assoc_dev_name != NULL)
tc->con_dev_name = devm_kstrdup(dev,
assoc_dev_name, GFP_KERNEL);
- list_add_tail(&tc->node, &cti_dev->trig_cons);
- cti_dev->nr_trig_con++;
- /* add connection usage bit info to overall info */
- drvdata->config.trig_in_use |= tc->con_in->used_mask;
- drvdata->config.trig_out_use |= tc->con_out->used_mask;
- return 0;
+}
+/* create a trigger connection with appropriately sized signal groups */ +struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs,
int out_sigs)
+{
- struct cti_trig_con *tc = NULL;
- struct cti_trig_grp *in = NULL, *out = NULL;
- tc = devm_kzalloc(dev, sizeof(struct cti_trig_con), GFP_KERNEL);
- if (!tc)
return tc;
- in = devm_kzalloc(dev,
offsetof(struct cti_trig_grp, sig_types[in_sigs]),
GFP_KERNEL);
- if (!in)
return NULL;
- out = devm_kzalloc(dev,
offsetof(struct cti_trig_grp, sig_types[out_sigs]),
GFP_KERNEL);
- if (!out)
return NULL;
- tc->con_in = in;
- tc->con_out = out;
- tc->con_in->nr_sigs = in_sigs;
- tc->con_out->nr_sigs = out_sigs;
- return tc;
+}
+/*
- Add a default connection if nothing else is specified.
- single connection based on max in/out info, no assoc device
- */
+int cti_add_default_connection(struct device *dev, struct cti_drvdata *drvdata) +{
- int ret = 0;
- int n_trigs = drvdata->config.nr_trig_max;
- u32 n_trig_mask = GENMASK(n_trigs - 1, 0);
- struct cti_trig_con *tc = NULL;
- /*
* Assume max trigs for in and out,
* all used, default sig types allocated
*/
- tc = cti_allocate_trig_con(dev, n_trigs, n_trigs);
- if (!tc)
return -ENOMEM;
- tc->con_in->used_mask = n_trig_mask;
- tc->con_out->used_mask = n_trig_mask;
- ret = cti_add_connection_entry(dev, drvdata, tc, NULL, "default");
- return ret;
+}
+/** cti ect operations **/ +int cti_enable(struct coresight_device *csdev) +{
- struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev);
- /* enable hardware with refcount */
- return cti_enable_hw(drvdata, true);
+}
+int cti_disable(struct coresight_device *csdev) +{
- struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev);
- /* disable hardware with refcount */
- return cti_disable_hw(drvdata, true);
+}
+const struct coresight_ops_ect cti_ops_ect = {
- .enable = cti_enable,
- .disable = cti_disable,
+};
+const struct coresight_ops cti_ops = {
- .ect_ops = &cti_ops_ect,
+};
+/*
- Free up CTI specific resources
- called by dev->release, need to call down to underlying csdev release.
- */
+static void cti_device_release(struct device *dev) +{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_drvdata *ect_item, *ect_tmp;
- mutex_lock(&ect_mutex);
- /* remove from the list */
- list_for_each_entry_safe(ect_item, ect_tmp, &ect_net, node) {
if (ect_item == drvdata) {
list_del(&ect_item->node);
goto ect_list_item_removed;
}
- }
+ect_list_item_removed:
- mutex_unlock(&ect_mutex);
- if (drvdata->csdev_release)
drvdata->csdev_release(dev);
+}
+static int cti_probe(struct amba_device *adev, const struct amba_id *id) +{
- int ret = 0;
- void __iomem *base;
- struct device *dev = &adev->dev;
- struct cti_drvdata *drvdata = NULL;
- struct coresight_desc cti_desc;
- struct coresight_platform_data *pdata = NULL;
- struct resource *res = &adev->res;
- /* driver data*/
- drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
- if (!drvdata) {
ret = -ENOMEM;
dev_info(dev, "%s, mem err\n", __func__);
goto err_out;
- }
- /* Validity for the resource is already checked by the AMBA core */
- base = devm_ioremap_resource(dev, res);
- if (IS_ERR(base)) {
ret = PTR_ERR(base);
dev_info(dev, "%s, remap err\n", __func__);
goto err_out;
- }
- drvdata->base = base;
- dev_set_drvdata(dev, drvdata);
- /* default CTI device info */
- drvdata->ctidev.cpu = -1;
- drvdata->ctidev.nr_trig_con = 0;
- drvdata->ctidev.ctm_id = 0;
- INIT_LIST_HEAD(&drvdata->ctidev.trig_cons);
- spin_lock_init(&drvdata->spinlock);
- /* initialise CTI driver config values */
- cti_set_default_config(dev, drvdata);
- /* Parse the .dts for connections and signals */
- pdata = coresight_cti_get_platform_data(dev);
- if (IS_ERR(pdata)) {
dev_info(dev, "coresight_cti_get_platform_data err\n");
ret = PTR_ERR(pdata);
goto err_out;
- }
- /* default to powered - could change on PM notifications */
- drvdata->config.hw_powered = true;
- /* set up device name - will depend if cpu bound or otherwise */
- if (drvdata->ctidev.cpu >= 0)
cti_desc.name = devm_kasprintf(dev, GFP_KERNEL, "cti_cpu%d",
drvdata->ctidev.cpu);
- else
cti_desc.name = coresight_alloc_device_name(&cti_sys_devs, dev);
- if (!cti_desc.name) {
ret = -ENOMEM;
goto err_out;
- }
- /* set up coresight component description */
- cti_desc.pdata = pdata;
- cti_desc.type = CORESIGHT_DEV_TYPE_ECT;
- cti_desc.subtype.ect_subtype = CORESIGHT_DEV_SUBTYPE_ECT_CTI;
- cti_desc.ops = &cti_ops;
- cti_desc.groups = coresight_cti_groups;
- cti_desc.dev = dev;
- drvdata->csdev = coresight_register(&cti_desc);
- if (IS_ERR(drvdata->csdev)) {
ret = PTR_ERR(drvdata->csdev);
goto err_out;
- }
- /* add to list of CTI devices */
- mutex_lock(&ect_mutex);
- list_add(&drvdata->node, &ect_net);
- mutex_unlock(&ect_mutex);
- /* set up release chain */
- drvdata->csdev_release = drvdata->csdev->dev.release;
- drvdata->csdev->dev.release = cti_device_release;
I really like what you've done here.
- /* all done - dec pm refcount */
- pm_runtime_put(&adev->dev);
- dev_info(dev, "%s: CTI initialized\n", cti_desc.name);
- return 0;
+err_out:
- return ret;
+}
+static struct amba_cs_uci_id uci_id_cti[] = {
- {
/* CTI UCI data */
.devarch = 0x47701a14, /* CTI v2 */
.devarch_mask = 0xfff0ffff,
.devtype = 0x00000014, /* maj(0x4-debug) min(0x1-ECT) */
- }
+};
+static const struct amba_id cti_ids[] = {
- CS_AMBA_ID(0x000bb906), /* Coresight CTI (SoC 400), C-A72, C-A57 */
- CS_AMBA_ID(0x000bb922), /* CTI - C-A8 */
- CS_AMBA_ID(0x000bb9a8), /* CTI - C-A53 */
- CS_AMBA_ID(0x000bb9aa), /* CTI - C-A73 */
- CS_AMBA_UCI_ID(0x000bb9da, uci_id_cti), /* CTI - C-A35 */
- CS_AMBA_UCI_ID(0x000bb9ed, uci_id_cti), /* Coresight CTI (SoC 600) */
- { 0, 0},
+};
+static struct amba_driver cti_driver = {
- .drv = {
.name = "coresight-cti",
.owner = THIS_MODULE,
.suppress_bind_attrs = true,
- },
- .probe = cti_probe,
- .id_table = cti_ids,
+}; +builtin_amba_driver(cti_driver); diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h new file mode 100644 index 000000000000..717035a9aa72 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -0,0 +1,192 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (c) 2018 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#ifndef _CORESIGHT_CORESIGHT_CTI_H +#define _CORESIGHT_CORESIGHT_CTI_H
+#include <asm/local.h> +#include <linux/spinlock.h> +#include "coresight-priv.h"
+/*
- Device registers
- 0x000 - 0x144: CTI programming and status
- 0xEDC - 0xEF8: CTI integration test.
- 0xF00 - 0xFFC: Coresight management registers.
- */
+/* CTI programming registers */ +#define CTICONTROL 0x000 +#define CTIINTACK 0x010 +#define CTIAPPSET 0x014 +#define CTIAPPCLEAR 0x018 +#define CTIAPPPULSE 0x01C +#define CTIINEN(n) (0x020 + (4 * n)) +#define CTIOUTEN(n) (0x0A0 + (4 * n)) +#define CTITRIGINSTATUS 0x130 +#define CTITRIGOUTSTATUS 0x134 +#define CTICHINSTATUS 0x138 +#define CTICHOUTSTATUS 0x13C +#define CTIGATE 0x140 +#define ASICCTL 0x144 +/* Integration test registers */ +#define ITCHINACK 0xEDC /* WO CTI CSSoc 400 only*/ +#define ITTRIGINACK 0xEE0 /* WO CTI CSSoc 400 only*/ +#define ITCHOUT 0xEE4 /* WO RW-600 */ +#define ITTRIGOUT 0xEE8 /* WO RW-600 */ +#define ITCHOUTACK 0xEEC /* RO CTI CSSoc 400 only*/ +#define ITTRIGOUTACK 0xEF0 /* RO CTI CSSoc 400 only*/ +#define ITCHIN 0xEF4 /* RO */ +#define ITTRIGIN 0xEF8 /* RO */ +/* management registers */ +#define CTIDEVAFF0 0xFA8 +#define CTIDEVAFF1 0xFAC
+/*
- CTI CSSoc 600 has a max of 32 trigger signals per direction.
- CTI CSSoc 400 has 8 IO triggers - other CTIs can be impl def.
- Max of in and out defined in the DEVID register.
- pick up actual number used from .dts parameters if present.
- */
+#define CTIINOUTEN_MAX 32
+/**
- Group of related trigger signals
- @nr_sigs: number of signals in the group.
- @used_mask: bitmask representing the signal indexes in the group.
- @sig_types: array of types for the signals, length nr_sigs.
- */
+struct cti_trig_grp {
- int nr_sigs;
- u32 used_mask;
- int sig_types[0];
+};
+/**
- Trigger connection - connection between a CTI and other (coresight) device
- lists input and output trigger signals for the device
- @con_in: connected CTIIN signals for the device.
- @con_out: connected CTIOUT signals for the device.
- @con_dev: coresight device connected to the CTI, NULL if not CS device
- @con_dev_name: name of connected device (CS or CPU)
- @node: entry node in list of connections.
- */
+struct cti_trig_con {
- struct cti_trig_grp *con_in;
- struct cti_trig_grp *con_out;
- struct coresight_device *con_dev;
- char *con_dev_name;
- struct list_head node;
+};
+/**
- struct cti_device - description of CTI device properties.
- @nt_trig_con: Number of external devices connected to this device.
- @ctm_id: which CTM this device is connected to (by default it is
assumed there is a single CTM per SoC, ID 0).
- @trig_cons: list of connections to this device.
- @cpu: CPU ID if associated with CPU, -1 otherwise.
- */
+struct cti_device {
- int nr_trig_con;
- u32 ctm_id;
- struct list_head trig_cons;
- int cpu;
+};
+/**
- struct cti_config - configuration of the CTI device hardware
- Hardware description from RO ID regs
- @nr_trig_max: Max number of trigger signals implemented on device.
(max of trig_in or trig_out)
- @nr_ctm_channels: number of available CTM channels
- Cti enable control
Are the above 2 lines supposed to be part of @nr_ctm_channels? If so there is a spurious newline and the beginning of the second line needs to be aligned with the 'n' of number.
- @enable_req_count: CTI is enabled alongside >=1 associated devices.
- @hw_enabled: true if hw is currently enabled.
- @hw_powered: true if associated cpu powered on, or no cpu.
- Registered triggers and filtering
Same here
- @trig_in_use: bitfield of in triggers registered as in use.
- @trig_out_use: bitfield of out triggers registered as in use.
- @trig_out_filter: bitfield of out triggers that are blocked if filter
- enabled. Typically this would be dbgreq / restart on a core CTI.
Align the second line with "bitfield".
- @trig_filter_enable: 1 if filtering enabled.
- @xtrig_rchan_sel: channel selection for xtrigger connection show.
- Cti software programmable regs:
Same as above
- @ctiappset: CTI Software application channel set.
- @ctiinout_sel: register selector for INEN and OUTEN regs.
- @ctiinen: enable input trigger to a channel.
- @ctiouten: enable output trigger from a channel.
- @ctigate: gate channel output from CTI to CTM.
- @asicctl: asic control register.
- */
+struct cti_config {
- /* hardware description */
- int nr_ctm_channels;
- int nr_trig_max;
- /* cti enable control */
- atomic_t enable_req_count;
- bool hw_enabled;
- bool hw_powered;
- /* registered triggers and filtering */
- u32 trig_in_use;
- u32 trig_out_use;
- u32 trig_out_filter;
- bool trig_filter_enable;
- u8 xtrig_rchan_sel;
- /* cti cross trig programmable regs */
- u32 ctiappset;
- u8 ctiinout_sel;
- u32 ctiinen[CTIINOUTEN_MAX];
- u32 ctiouten[CTIINOUTEN_MAX];
- u32 ctigate;
- u32 asicctl;
+};
+/**
- struct cti_drvdata - specifics for the CTI device
- @base: Memory mapped base address for this component..
- @csdev: Standard CoreSight device information.
- @ctidev: Extra information needed by the CTI/CTM framework.
- @spinlock: Control data access to one at a time.
- @config: Configuration data for this CTI device.
- @node: List entry of this device in the list of CTI devices.
- @csdev_release: release function for underlying coresight_device.
- */
+struct cti_drvdata {
- void __iomem *base;
- struct coresight_device *csdev;
- struct cti_device ctidev;
- spinlock_t spinlock;
- struct cti_config config;
- struct list_head node;
- void (*csdev_release)(struct device *dev);
+};
+/* private cti driver fns & vars */ +extern const struct attribute_group *coresight_cti_groups[]; +int cti_add_default_connection(struct device *dev,
struct cti_drvdata *drvdata);
+int cti_add_connection_entry(struct device *dev, struct cti_drvdata *drvdata,
struct cti_trig_con *tc,
struct coresight_device *csdev,
const char *assoc_dev_name);
+struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs,
int out_sigs);
+int cti_enable(struct coresight_device *csdev); +int cti_disable(struct coresight_device *csdev); +struct coresight_platform_data * +coresight_cti_get_platform_data(struct device *dev);
+#endif /* _CORESIGHT_CORESIGHT_CTI_H */ diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 6453c67a4d01..64ff810394f9 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -972,6 +972,9 @@ static struct device_type coresight_dev_type[] = { { .name = "helper", },
- {
.name = "ect",
- },
}; static void coresight_device_release(struct device *dev) @@ -979,6 +982,7 @@ static void coresight_device_release(struct device *dev) struct coresight_device *csdev = to_coresight_device(dev); fwnode_handle_put(csdev->dev.fwnode);
Spurious newline
kfree(csdev->refcnt); kfree(csdev); } diff --git a/include/linux/coresight.h b/include/linux/coresight.h index a2b68823717b..2a23c3cdf8e4 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -41,6 +41,7 @@ enum coresight_dev_type { CORESIGHT_DEV_TYPE_LINKSINK, CORESIGHT_DEV_TYPE_SOURCE, CORESIGHT_DEV_TYPE_HELPER,
- CORESIGHT_DEV_TYPE_ECT,
}; enum coresight_dev_subtype_sink { @@ -68,6 +69,12 @@ enum coresight_dev_subtype_helper { CORESIGHT_DEV_SUBTYPE_HELPER_CATU, }; +/* Embedded Cross Trigger (ECT) sub-types */ +enum coresight_dev_subtype_ect {
- CORESIGHT_DEV_SUBTYPE_ECT_NONE,
- CORESIGHT_DEV_SUBTYPE_ECT_CTI,
+};
/**
- union coresight_dev_subtype - further characterisation of a type
- @sink_subtype: type of sink this component is, as defined
@@ -78,6 +85,8 @@ enum coresight_dev_subtype_helper {
by @coresight_dev_subtype_source.
- @helper_subtype: type of helper this component is, as defined
by @coresight_dev_subtype_helper.
- @ect_subtype: type of cross trigger this component is, as
*/
defined by @coresight_dev_subtype_ect
union coresight_dev_subtype { /* We have some devices which acts as LINK and SINK */ @@ -87,6 +96,7 @@ union coresight_dev_subtype { }; enum coresight_dev_subtype_source source_subtype; enum coresight_dev_subtype_helper helper_subtype;
- enum coresight_dev_subtype_ect ect_subtype;
}; /** @@ -196,6 +206,7 @@ static struct coresight_dev_list (var) = { \ #define sink_ops(csdev) csdev->ops->sink_ops #define link_ops(csdev) csdev->ops->link_ops #define helper_ops(csdev) csdev->ops->helper_ops +#define ect_ops(csdev) csdev->ops->ect_ops /**
- struct coresight_ops_sink - basic operations for a sink
@@ -262,11 +273,23 @@ struct coresight_ops_helper { int (*disable)(struct coresight_device *csdev, void *data); }; +/**
- struct coresight_ops_ect - Ops for an embedded cross trigger device
- @enable : Enable the device
- @disable : Disable the device
- */
+struct coresight_ops_ect {
- int (*enable)(struct coresight_device *csdev);
- int (*disable)(struct coresight_device *csdev);
+};
struct coresight_ops { const struct coresight_ops_sink *sink_ops; const struct coresight_ops_link *link_ops; const struct coresight_ops_source *source_ops; const struct coresight_ops_helper *helper_ops;
- const struct coresight_ops_ect *ect_ops;
};
#ifdef CONFIG_CORESIGHT
2.17.1
On Mon, Aug 19, 2019 at 10:13:47PM +0100, Mike Leach wrote:
This introduces a baseline CTI driver and associated configuration files.
Uses the platform agnostic naming standard for CoreSight devices, along with a generic platform probing method that currently supports device tree descriptions, but allows for the ACPI bindings to be added once these have been defined for the CTI devices.
Driver will probe for the device on the AMBA bus, and load the CTI driver on CoreSight ID match to CTI IDs in tables.
Initial sysfs support for enable / disable provided.
Default CTI interconnection data is generated based on hardware register signal counts, with no additional connection information.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Kconfig | 12 + drivers/hwtracing/coresight/Makefile | 4 + .../coresight/coresight-cti-platform.c | 75 +++ .../hwtracing/coresight/coresight-cti-sysfs.c | 72 +++ drivers/hwtracing/coresight/coresight-cti.c | 451 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.h | 192 ++++++++ drivers/hwtracing/coresight/coresight.c | 4 + include/linux/coresight.h | 23 + 8 files changed, 833 insertions(+) create mode 100644 drivers/hwtracing/coresight/coresight-cti-platform.c create mode 100644 drivers/hwtracing/coresight/coresight-cti-sysfs.c create mode 100644 drivers/hwtracing/coresight/coresight-cti.c create mode 100644 drivers/hwtracing/coresight/coresight-cti.h
[snip]
+static int cti_probe(struct amba_device *adev, const struct amba_id *id) +{
- int ret = 0;
- void __iomem *base;
- struct device *dev = &adev->dev;
- struct cti_drvdata *drvdata = NULL;
- struct coresight_desc cti_desc;
- struct coresight_platform_data *pdata = NULL;
- struct resource *res = &adev->res;
- /* driver data*/
- drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
- if (!drvdata) {
ret = -ENOMEM;
dev_info(dev, "%s, mem err\n", __func__);
goto err_out;
- }
- /* Validity for the resource is already checked by the AMBA core */
- base = devm_ioremap_resource(dev, res);
- if (IS_ERR(base)) {
ret = PTR_ERR(base);
dev_info(dev, "%s, remap err\n", __func__);
goto err_out;
- }
- drvdata->base = base;
- dev_set_drvdata(dev, drvdata);
- /* default CTI device info */
- drvdata->ctidev.cpu = -1;
- drvdata->ctidev.nr_trig_con = 0;
- drvdata->ctidev.ctm_id = 0;
- INIT_LIST_HEAD(&drvdata->ctidev.trig_cons);
- spin_lock_init(&drvdata->spinlock);
- /* initialise CTI driver config values */
- cti_set_default_config(dev, drvdata);
- /* Parse the .dts for connections and signals */
- pdata = coresight_cti_get_platform_data(dev);
- if (IS_ERR(pdata)) {
dev_info(dev, "coresight_cti_get_platform_data err\n");
ret = PTR_ERR(pdata);
goto err_out;
- }
- /* default to powered - could change on PM notifications */
- drvdata->config.hw_powered = true;
- /* set up device name - will depend if cpu bound or otherwise */
- if (drvdata->ctidev.cpu >= 0)
cti_desc.name = devm_kasprintf(dev, GFP_KERNEL, "cti_cpu%d",
drvdata->ctidev.cpu);
- else
cti_desc.name = coresight_alloc_device_name(&cti_sys_devs, dev);
- if (!cti_desc.name) {
ret = -ENOMEM;
goto err_out;
- }
- /* set up coresight component description */
- cti_desc.pdata = pdata;
- cti_desc.type = CORESIGHT_DEV_TYPE_ECT;
- cti_desc.subtype.ect_subtype = CORESIGHT_DEV_SUBTYPE_ECT_CTI;
- cti_desc.ops = &cti_ops;
- cti_desc.groups = coresight_cti_groups;
- cti_desc.dev = dev;
- drvdata->csdev = coresight_register(&cti_desc);
- if (IS_ERR(drvdata->csdev)) {
ret = PTR_ERR(drvdata->csdev);
goto err_out;
- }
- /* add to list of CTI devices */
- mutex_lock(&ect_mutex);
- list_add(&drvdata->node, &ect_net);
- mutex_unlock(&ect_mutex);
- /* set up release chain */
- drvdata->csdev_release = drvdata->csdev->dev.release;
- drvdata->csdev->dev.release = cti_device_release;
- /* all done - dec pm refcount */
- pm_runtime_put(&adev->dev);
- dev_info(dev, "%s: CTI initialized\n", cti_desc.name);
I was booting this set and found the following on the console:
[ 6.861925] coresight stm0: STM32 initialized [ 6.866879] coresight-cti 22020000.cti: cti_cpu1: CTI initialized [ 6.873414] coresight etm2: CPU2: ETM v4.0 initialized [ 6.878733] coresight-cti 22120000.cti: cti_cpu2: CTI initialized [ 6.885189] coresight-cti 23020000.cti: cti_cpu0: CTI initialized [ 6.891742] coresight etm3: CPU3: ETM v4.0 initialized [ 6.897066] coresight-cti 23120000.cti: cti_cpu3: CTI initialized [ 6.903421] coresight etm4: CPU4: ETM v4.0 initialized [ 6.908744] coresight-cti 23220000.cti: cti_cpu4: CTI initialized [ 6.915104] coresight etm5: CPU5: ETM v4.0 initialized [ 6.920428] coresight-cti 23320000.cti: cti_cpu5: CTI initialized [ 6.926759] coresight-cti 20020000.cti: cti_sys0: CTI initialized [ 6.933034] coresight-cti 20110000.cti: cti_sys1: CTI initialized [ 6.939611] coresight etm1: CPU1: ETM v4.0 initialized [ 6.944923] coresight etm0: CPU0: ETM v4.0 initialized
I think it is a tad messy, especially after all the efforts what were put in to refactor our naming convention. If we just do:
dev_info(&drvdata->csdev->dev, "CTI initialized\n");
We get the following:
[ 5.709155] coresight stm0: STM32 initialized [ 5.714106] coresight cti_cpu1: CTI initialized [ 5.719120] coresight etm2: CPU2: ETM v4.0 initialized [ 5.724446] coresight cti_cpu2: CTI initialized [ 5.729363] coresight cti_cpu0: CTI initialized [ 5.734368] coresight etm3: CPU3: ETM v4.0 initialized [ 5.739693] coresight cti_cpu3: CTI initialized [ 5.744505] coresight etm4: CPU4: ETM v4.0 initialized [ 5.749827] coresight cti_cpu4: CTI initialized [ 5.754635] coresight etm5: CPU5: ETM v4.0 initialized [ 5.759957] coresight cti_cpu5: CTI initialized [ 5.764730] coresight cti_sys0: CTI initialized [ 5.769468] coresight cti_sys1: CTI initialized [ 5.774425] coresight etm1: CPU1: ETM v4.0 initialized [ 5.779733] coresight etm0: CPU0: ETM v4.0 initialized
In my opinion that is much cleaner, especially when ACPI will get thrown in the mix.
Mathieu
- return 0;
+err_out:
- return ret;
+}
+static struct amba_cs_uci_id uci_id_cti[] = {
- {
/* CTI UCI data */
.devarch = 0x47701a14, /* CTI v2 */
.devarch_mask = 0xfff0ffff,
.devtype = 0x00000014, /* maj(0x4-debug) min(0x1-ECT) */
- }
+};
+static const struct amba_id cti_ids[] = {
- CS_AMBA_ID(0x000bb906), /* Coresight CTI (SoC 400), C-A72, C-A57 */
- CS_AMBA_ID(0x000bb922), /* CTI - C-A8 */
- CS_AMBA_ID(0x000bb9a8), /* CTI - C-A53 */
- CS_AMBA_ID(0x000bb9aa), /* CTI - C-A73 */
- CS_AMBA_UCI_ID(0x000bb9da, uci_id_cti), /* CTI - C-A35 */
- CS_AMBA_UCI_ID(0x000bb9ed, uci_id_cti), /* Coresight CTI (SoC 600) */
- { 0, 0},
+};
+static struct amba_driver cti_driver = {
- .drv = {
.name = "coresight-cti",
.owner = THIS_MODULE,
.suppress_bind_attrs = true,
- },
- .probe = cti_probe,
- .id_table = cti_ids,
+}; +builtin_amba_driver(cti_driver); diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h new file mode 100644 index 000000000000..717035a9aa72 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -0,0 +1,192 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (c) 2018 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#ifndef _CORESIGHT_CORESIGHT_CTI_H +#define _CORESIGHT_CORESIGHT_CTI_H
+#include <asm/local.h> +#include <linux/spinlock.h> +#include "coresight-priv.h"
+/*
- Device registers
- 0x000 - 0x144: CTI programming and status
- 0xEDC - 0xEF8: CTI integration test.
- 0xF00 - 0xFFC: Coresight management registers.
- */
+/* CTI programming registers */ +#define CTICONTROL 0x000 +#define CTIINTACK 0x010 +#define CTIAPPSET 0x014 +#define CTIAPPCLEAR 0x018 +#define CTIAPPPULSE 0x01C +#define CTIINEN(n) (0x020 + (4 * n)) +#define CTIOUTEN(n) (0x0A0 + (4 * n)) +#define CTITRIGINSTATUS 0x130 +#define CTITRIGOUTSTATUS 0x134 +#define CTICHINSTATUS 0x138 +#define CTICHOUTSTATUS 0x13C +#define CTIGATE 0x140 +#define ASICCTL 0x144 +/* Integration test registers */ +#define ITCHINACK 0xEDC /* WO CTI CSSoc 400 only*/ +#define ITTRIGINACK 0xEE0 /* WO CTI CSSoc 400 only*/ +#define ITCHOUT 0xEE4 /* WO RW-600 */ +#define ITTRIGOUT 0xEE8 /* WO RW-600 */ +#define ITCHOUTACK 0xEEC /* RO CTI CSSoc 400 only*/ +#define ITTRIGOUTACK 0xEF0 /* RO CTI CSSoc 400 only*/ +#define ITCHIN 0xEF4 /* RO */ +#define ITTRIGIN 0xEF8 /* RO */ +/* management registers */ +#define CTIDEVAFF0 0xFA8 +#define CTIDEVAFF1 0xFAC
+/*
- CTI CSSoc 600 has a max of 32 trigger signals per direction.
- CTI CSSoc 400 has 8 IO triggers - other CTIs can be impl def.
- Max of in and out defined in the DEVID register.
- pick up actual number used from .dts parameters if present.
- */
+#define CTIINOUTEN_MAX 32
+/**
- Group of related trigger signals
- @nr_sigs: number of signals in the group.
- @used_mask: bitmask representing the signal indexes in the group.
- @sig_types: array of types for the signals, length nr_sigs.
- */
+struct cti_trig_grp {
- int nr_sigs;
- u32 used_mask;
- int sig_types[0];
+};
+/**
- Trigger connection - connection between a CTI and other (coresight) device
- lists input and output trigger signals for the device
- @con_in: connected CTIIN signals for the device.
- @con_out: connected CTIOUT signals for the device.
- @con_dev: coresight device connected to the CTI, NULL if not CS device
- @con_dev_name: name of connected device (CS or CPU)
- @node: entry node in list of connections.
- */
+struct cti_trig_con {
- struct cti_trig_grp *con_in;
- struct cti_trig_grp *con_out;
- struct coresight_device *con_dev;
- char *con_dev_name;
- struct list_head node;
+};
+/**
- struct cti_device - description of CTI device properties.
- @nt_trig_con: Number of external devices connected to this device.
- @ctm_id: which CTM this device is connected to (by default it is
assumed there is a single CTM per SoC, ID 0).
- @trig_cons: list of connections to this device.
- @cpu: CPU ID if associated with CPU, -1 otherwise.
- */
+struct cti_device {
- int nr_trig_con;
- u32 ctm_id;
- struct list_head trig_cons;
- int cpu;
+};
+/**
- struct cti_config - configuration of the CTI device hardware
- Hardware description from RO ID regs
- @nr_trig_max: Max number of trigger signals implemented on device.
(max of trig_in or trig_out)
- @nr_ctm_channels: number of available CTM channels
- Cti enable control
- @enable_req_count: CTI is enabled alongside >=1 associated devices.
- @hw_enabled: true if hw is currently enabled.
- @hw_powered: true if associated cpu powered on, or no cpu.
- Registered triggers and filtering
- @trig_in_use: bitfield of in triggers registered as in use.
- @trig_out_use: bitfield of out triggers registered as in use.
- @trig_out_filter: bitfield of out triggers that are blocked if filter
- enabled. Typically this would be dbgreq / restart on a core CTI.
- @trig_filter_enable: 1 if filtering enabled.
- @xtrig_rchan_sel: channel selection for xtrigger connection show.
- Cti software programmable regs:
- @ctiappset: CTI Software application channel set.
- @ctiinout_sel: register selector for INEN and OUTEN regs.
- @ctiinen: enable input trigger to a channel.
- @ctiouten: enable output trigger from a channel.
- @ctigate: gate channel output from CTI to CTM.
- @asicctl: asic control register.
- */
+struct cti_config {
- /* hardware description */
- int nr_ctm_channels;
- int nr_trig_max;
- /* cti enable control */
- atomic_t enable_req_count;
- bool hw_enabled;
- bool hw_powered;
- /* registered triggers and filtering */
- u32 trig_in_use;
- u32 trig_out_use;
- u32 trig_out_filter;
- bool trig_filter_enable;
- u8 xtrig_rchan_sel;
- /* cti cross trig programmable regs */
- u32 ctiappset;
- u8 ctiinout_sel;
- u32 ctiinen[CTIINOUTEN_MAX];
- u32 ctiouten[CTIINOUTEN_MAX];
- u32 ctigate;
- u32 asicctl;
+};
+/**
- struct cti_drvdata - specifics for the CTI device
- @base: Memory mapped base address for this component..
- @csdev: Standard CoreSight device information.
- @ctidev: Extra information needed by the CTI/CTM framework.
- @spinlock: Control data access to one at a time.
- @config: Configuration data for this CTI device.
- @node: List entry of this device in the list of CTI devices.
- @csdev_release: release function for underlying coresight_device.
- */
+struct cti_drvdata {
- void __iomem *base;
- struct coresight_device *csdev;
- struct cti_device ctidev;
- spinlock_t spinlock;
- struct cti_config config;
- struct list_head node;
- void (*csdev_release)(struct device *dev);
+};
+/* private cti driver fns & vars */ +extern const struct attribute_group *coresight_cti_groups[]; +int cti_add_default_connection(struct device *dev,
struct cti_drvdata *drvdata);
+int cti_add_connection_entry(struct device *dev, struct cti_drvdata *drvdata,
struct cti_trig_con *tc,
struct coresight_device *csdev,
const char *assoc_dev_name);
+struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs,
int out_sigs);
+int cti_enable(struct coresight_device *csdev); +int cti_disable(struct coresight_device *csdev); +struct coresight_platform_data * +coresight_cti_get_platform_data(struct device *dev);
+#endif /* _CORESIGHT_CORESIGHT_CTI_H */ diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 6453c67a4d01..64ff810394f9 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -972,6 +972,9 @@ static struct device_type coresight_dev_type[] = { { .name = "helper", },
- {
.name = "ect",
- },
}; static void coresight_device_release(struct device *dev) @@ -979,6 +982,7 @@ static void coresight_device_release(struct device *dev) struct coresight_device *csdev = to_coresight_device(dev); fwnode_handle_put(csdev->dev.fwnode);
- kfree(csdev->refcnt); kfree(csdev);
} diff --git a/include/linux/coresight.h b/include/linux/coresight.h index a2b68823717b..2a23c3cdf8e4 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -41,6 +41,7 @@ enum coresight_dev_type { CORESIGHT_DEV_TYPE_LINKSINK, CORESIGHT_DEV_TYPE_SOURCE, CORESIGHT_DEV_TYPE_HELPER,
- CORESIGHT_DEV_TYPE_ECT,
}; enum coresight_dev_subtype_sink { @@ -68,6 +69,12 @@ enum coresight_dev_subtype_helper { CORESIGHT_DEV_SUBTYPE_HELPER_CATU, }; +/* Embedded Cross Trigger (ECT) sub-types */ +enum coresight_dev_subtype_ect {
- CORESIGHT_DEV_SUBTYPE_ECT_NONE,
- CORESIGHT_DEV_SUBTYPE_ECT_CTI,
+};
/**
- union coresight_dev_subtype - further characterisation of a type
- @sink_subtype: type of sink this component is, as defined
@@ -78,6 +85,8 @@ enum coresight_dev_subtype_helper {
by @coresight_dev_subtype_source.
- @helper_subtype: type of helper this component is, as defined
by @coresight_dev_subtype_helper.
- @ect_subtype: type of cross trigger this component is, as
*/
defined by @coresight_dev_subtype_ect
union coresight_dev_subtype { /* We have some devices which acts as LINK and SINK */ @@ -87,6 +96,7 @@ union coresight_dev_subtype { }; enum coresight_dev_subtype_source source_subtype; enum coresight_dev_subtype_helper helper_subtype;
- enum coresight_dev_subtype_ect ect_subtype;
}; /** @@ -196,6 +206,7 @@ static struct coresight_dev_list (var) = { \ #define sink_ops(csdev) csdev->ops->sink_ops #define link_ops(csdev) csdev->ops->link_ops #define helper_ops(csdev) csdev->ops->helper_ops +#define ect_ops(csdev) csdev->ops->ect_ops /**
- struct coresight_ops_sink - basic operations for a sink
@@ -262,11 +273,23 @@ struct coresight_ops_helper { int (*disable)(struct coresight_device *csdev, void *data); }; +/**
- struct coresight_ops_ect - Ops for an embedded cross trigger device
- @enable : Enable the device
- @disable : Disable the device
- */
+struct coresight_ops_ect {
- int (*enable)(struct coresight_device *csdev);
- int (*disable)(struct coresight_device *csdev);
+};
struct coresight_ops { const struct coresight_ops_sink *sink_ops; const struct coresight_ops_link *link_ops; const struct coresight_ops_source *source_ops; const struct coresight_ops_helper *helper_ops;
- const struct coresight_ops_ect *ect_ops;
};
#ifdef CONFIG_CORESIGHT
2.17.1
Hi Mike
On 08/19/2019 10:13 PM, Mike Leach wrote:
This introduces a baseline CTI driver and associated configuration files.
Uses the platform agnostic naming standard for CoreSight devices, along with a generic platform probing method that currently supports device tree descriptions, but allows for the ACPI bindings to be added once these have been defined for the CTI devices.
Driver will probe for the device on the AMBA bus, and load the CTI driver on CoreSight ID match to CTI IDs in tables.
Initial sysfs support for enable / disable provided.
Default CTI interconnection data is generated based on hardware register signal counts, with no additional connection information.
Signed-off-by: Mike Leach mike.leach@linaro.org
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c new file mode 100644 index 000000000000..eb4f8a835c10 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2019, The Linux Foundation. All rights reserved.
- */
+#include <linux/of.h>
+#include "coresight-cti.h"
+#ifdef CONFIG_OF +/* get the hardware configuration & connection data. */ +int of_cti_get_hw_data(struct device *dev,
struct device_node *np,
struct cti_drvdata *drvdata)
nit: The parameter np seems superfluous. You don't use it now. Even if you wanted to use it, you could grab it from the dev already.
+{
- int rc = 0;
- struct cti_device *cti_dev = &drvdata->ctidev;
- /* if no connections, just add a single default based on max IN-OUT */
- if (cti_dev->nr_trig_con == 0)
rc = cti_add_default_connection(dev, drvdata);
- return rc;
+}
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c new file mode 100644 index 000000000000..a832b8c6b866 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
+/* basic attributes */ +static ssize_t enable_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- int enable_req;
- bool enabled, powered;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- ssize_t size = 0;
- enable_req = atomic_read(&drvdata->config.enable_req_count);
- spin_lock(&drvdata->spinlock);
- powered = drvdata->config.hw_powered;
- enabled = drvdata->config.hw_enabled;
- spin_unlock(&drvdata->spinlock);
- if (powered) {
size = scnprintf(buf, PAGE_SIZE, "cti %s; powered;\n",
enabled ? "enabled" : "disabled");
- } else {
size = scnprintf(buf, PAGE_SIZE, "cti %s; unpowered;\n",
enable_req ? "enable req" : "disabled");
- }
- return size;
+}
diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c new file mode 100644 index 000000000000..b56d9a02c4b4 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti.c
+#include "coresight-cti.h"
+/**
- CTI devices can be associated with a PE, or be connected to CoreSight
- hardware. We have a list of all CTIs irrespective of CPU bound or
- otherwise.
- We assume that the non-CPU CTIs are always powered as we do with sinks etc.
- We leave the client to figure out if all the CTIs are interconnected with
- the same CTM, in general this is the case but does not always have to be.
- */
+/* net of CTI devices connected via CTM */ +LIST_HEAD(ect_net);
+/* protect the list */ +static DEFINE_MUTEX(ect_mutex);
+#define csdev_to_cti_drvdata(csdev) \
- dev_get_drvdata(csdev->dev.parent)
+/* disable hardware */ +static int cti_disable_hw(struct cti_drvdata *drvdata, bool update_refcount) +{
- struct cti_config *config = &drvdata->config;
- struct device *dev = &drvdata->csdev->dev;
- spin_lock(&drvdata->spinlock);
- /* check refcount - disable on 0 */
- if (update_refcount &&
(atomic_dec_return(&drvdata->config.enable_req_count) > 0))
goto cti_not_disabled;
If you really need to do something like this, you could refactor the function as follows :
/* Called with drvdata->spinlock held */
static int __cti_disable_hw(drvdata) {
- /* no need to do anything if disabled or cpu unpowered */
- if (!config->hw_enabled || !config->hw_powered)
goto cti_not_disabled;
- CS_UNLOCK(drvdata->base);
- /* disable CTI */
- writel_relaxed(0, drvdata->base + CTICONTROL);
- config->hw_enabled = false;
- coresight_disclaim_device_unlocked(drvdata->base);
- CS_LOCK(drvdata->base);
- spin_unlock(&drvdata->spinlock);
- pm_runtime_put(dev);
- return 0;
}
And make the decision of calling this from cti_disable_hw() based on refcount. And where you may not want to check the refcount call the __cti_disable_hw() directly.
- /* not disabled this call */
+cti_not_disabled:
- spin_unlock(&drvdata->spinlock);
- return 0;
+}
+/*
- Add a connection entry to the list of connections for this
- CTI device.
- */
+int cti_add_connection_entry(struct device *dev, struct cti_drvdata *drvdata,
struct cti_trig_con *tc,
struct coresight_device *csdev,
const char *assoc_dev_name)
+{
- struct cti_device *cti_dev = &drvdata->ctidev;
- tc->con_dev = csdev;
- /*
* Prefer actual associated CS device dev name to supplied value -
* which is likely to be node name / other conn name.
*/
- if (csdev)
tc->con_dev_name = devm_kstrdup(dev,
dev_name(&csdev->dev),
GFP_KERNEL);
- else if (assoc_dev_name != NULL)
tc->con_dev_name = devm_kstrdup(dev,
assoc_dev_name, GFP_KERNEL);
- list_add_tail(&tc->node, &cti_dev->trig_cons);
- cti_dev->nr_trig_con++;
- /* add connection usage bit info to overall info */
- drvdata->config.trig_in_use |= tc->con_in->used_mask;
- drvdata->config.trig_out_use |= tc->con_out->used_mask;
- return 0;
+}
+/* create a trigger connection with appropriately sized signal groups */ +struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs,
int out_sigs)
+{
- struct cti_trig_con *tc = NULL;
- struct cti_trig_grp *in = NULL, *out = NULL;
- tc = devm_kzalloc(dev, sizeof(struct cti_trig_con), GFP_KERNEL);
- if (!tc)
return tc;
- in = devm_kzalloc(dev,
offsetof(struct cti_trig_grp, sig_types[in_sigs]),
GFP_KERNEL);
- if (!in)
return NULL;
- out = devm_kzalloc(dev,
offsetof(struct cti_trig_grp, sig_types[out_sigs]),
GFP_KERNEL);
- if (!out)
return NULL;
- tc->con_in = in;
- tc->con_out = out;
- tc->con_in->nr_sigs = in_sigs;
- tc->con_out->nr_sigs = out_sigs;
- return tc;
+}
+/*
- Add a default connection if nothing else is specified.
- single connection based on max in/out info, no assoc device
- */
+int cti_add_default_connection(struct device *dev, struct cti_drvdata *drvdata) +{
- int ret = 0;
- int n_trigs = drvdata->config.nr_trig_max;
- u32 n_trig_mask = GENMASK(n_trigs - 1, 0);
- struct cti_trig_con *tc = NULL;
- /*
* Assume max trigs for in and out,
* all used, default sig types allocated
*/
- tc = cti_allocate_trig_con(dev, n_trigs, n_trigs);
- if (!tc)
return -ENOMEM;
- tc->con_in->used_mask = n_trig_mask;
- tc->con_out->used_mask = n_trig_mask;
- ret = cti_add_connection_entry(dev, drvdata, tc, NULL, "default");
- return ret;
+}
+/** cti ect operations **/ +int cti_enable(struct coresight_device *csdev) +{
- struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev);
- /* enable hardware with refcount */
- return cti_enable_hw(drvdata, true);
+}
+int cti_disable(struct coresight_device *csdev) +{
- struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev);
- /* disable hardware with refcount */
- return cti_disable_hw(drvdata, true);
+}
+const struct coresight_ops_ect cti_ops_ect = {
- .enable = cti_enable,
- .disable = cti_disable,
+};
+const struct coresight_ops cti_ops = {
- .ect_ops = &cti_ops_ect,
+};
+/*
- Free up CTI specific resources
- called by dev->release, need to call down to underlying csdev release.
- */
+static void cti_device_release(struct device *dev) +{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_drvdata *ect_item, *ect_tmp;
- mutex_lock(&ect_mutex);
- /* remove from the list */
- list_for_each_entry_safe(ect_item, ect_tmp, &ect_net, node) {
if (ect_item == drvdata) {
list_del(&ect_item->node);
goto ect_list_item_removed;
nit: s/goto ../break ?
}
- }
+ect_list_item_removed:
- mutex_unlock(&ect_mu tex);
- if (drvdata->csdev_release)
drvdata->csdev_release(dev);
+}
Rest looks good to me.
Cheers Suzuki
More on this - see below...
On Mon, 19 Aug 2019 at 15:14, Mike Leach mike.leach@linaro.org wrote:
+/*
- Platform data for the CTI does not have the same connection info
- as the trace path components. Implement specific function to
- avoid warnings of missing connections.
- */
+int of_get_coresight_cti_platform_data(struct device *dev,
struct coresight_platform_data *pdata)
+{
int ret = 0;
struct device_node *node = dev->of_node;
struct cti_drvdata *drvdata = dev_get_drvdata(dev);
/* get some CTI specifics */
ret = of_cti_get_hw_data(dev, node, drvdata);
return ret;
+} +#else +inline int +of_get_coresight_cti_platform_data(struct device *dev,
struct coresight_platform_data *pdata)
+{
return -ENOENT;
+}
+#endif
+struct coresight_platform_data * +coresight_cti_get_platform_data(struct device *dev) +{
int ret = -ENOENT;
struct coresight_platform_data *pdata = NULL;
struct fwnode_handle *fwnode = dev_fwnode(dev);
if (IS_ERR_OR_NULL(fwnode))
goto error;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
ret = -ENOMEM;
goto error;
}
if (is_of_node(fwnode))
ret = of_get_coresight_cti_platform_data(dev, pdata);
I've been spending a fair amount of time looking at the code in patch 06. There is nothing wrong with it but in my opinion we can keep things as they currently are and do a massive refactoring when introducing support for ACPI or just change our ways now. We carry 'dev' through calls to of_cti_create_v8_connections() and of_cti_create_v8_etm_connections(). Both function carry a lot of code that will be common to the future ACPI support.
Taking a closer look at of_cti_create_v8_connections(), only of_cti_get_cpu_at_node() is OF dependent. I suggest to create a generic function that would do a is_of_node() and from there call of_cti_get_cpu_at_node(), opening an easy path to ACPI support. The same process applies to of_cti_create_v8_etm_connection(). I suggest to spin off a new function to check for the presence of the associated device that would do the right thing based on the FW method used. Same for getting the associated device. That way of_cti_create_v8_connections() and of_cti_create_v8_etm_connection() become cti_create_v8_connections() and cti_create_v8_etm_connection(), providing a common core and a quick path for ACPI support.
We will have to do something like that anyway, so might as well do it right now. You can also call me a bike shedder.
Mathieu
Mathieu, Suzuki, Leo,
Changes made largely in line with your suggestions. of_ support rationalised in later patches to use fwnode wherever possible. removed superfluous parameter from cti_enable/disable_hw() calls.
Thanks for the feedback.
Mike
On Tue, 1 Oct 2019 at 20:42, Mathieu Poirier mathieu.poirier@linaro.org wrote:
More on this - see below...
On Mon, 19 Aug 2019 at 15:14, Mike Leach mike.leach@linaro.org wrote:
+/*
- Platform data for the CTI does not have the same connection info
- as the trace path components. Implement specific function to
- avoid warnings of missing connections.
- */
+int of_get_coresight_cti_platform_data(struct device *dev,
struct coresight_platform_data *pdata)
+{
int ret = 0;
struct device_node *node = dev->of_node;
struct cti_drvdata *drvdata = dev_get_drvdata(dev);
/* get some CTI specifics */
ret = of_cti_get_hw_data(dev, node, drvdata);
return ret;
+} +#else +inline int +of_get_coresight_cti_platform_data(struct device *dev,
struct coresight_platform_data *pdata)
+{
return -ENOENT;
+}
+#endif
+struct coresight_platform_data * +coresight_cti_get_platform_data(struct device *dev) +{
int ret = -ENOENT;
struct coresight_platform_data *pdata = NULL;
struct fwnode_handle *fwnode = dev_fwnode(dev);
if (IS_ERR_OR_NULL(fwnode))
goto error;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
ret = -ENOMEM;
goto error;
}
if (is_of_node(fwnode))
ret = of_get_coresight_cti_platform_data(dev, pdata);
I've been spending a fair amount of time looking at the code in patch 06. There is nothing wrong with it but in my opinion we can keep things as they currently are and do a massive refactoring when introducing support for ACPI or just change our ways now. We carry 'dev' through calls to of_cti_create_v8_connections() and of_cti_create_v8_etm_connections(). Both function carry a lot of code that will be common to the future ACPI support.
Taking a closer look at of_cti_create_v8_connections(), only of_cti_get_cpu_at_node() is OF dependent. I suggest to create a generic function that would do a is_of_node() and from there call of_cti_get_cpu_at_node(), opening an easy path to ACPI support. The same process applies to of_cti_create_v8_etm_connection(). I suggest to spin off a new function to check for the presence of the associated device that would do the right thing based on the FW method used. Same for getting the associated device. That way of_cti_create_v8_connections() and of_cti_create_v8_etm_connection() become cti_create_v8_connections() and cti_create_v8_etm_connection(), providing a common core and a quick path for ACPI support.
We will have to do something like that anyway, so might as well do it right now. You can also call me a bike shedder.
Mathieu
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
Adds sysfs access to the coresight management registers.
Signed-off-by: Mike Leach mike.leach@linaro.org --- .../hwtracing/coresight/coresight-cti-sysfs.c | 67 ++++++++++++++++++- drivers/hwtracing/coresight/coresight-priv.h | 1 + 2 files changed, 66 insertions(+), 2 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index a832b8c6b866..20a9b30c9755 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -34,8 +34,7 @@ static ssize_t enable_show(struct device *dev, return size; }
-static ssize_t enable_store(struct device *dev, - struct device_attribute *attr, +static ssize_t enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int ret = 0; @@ -56,9 +55,67 @@ static ssize_t enable_store(struct device *dev, } static DEVICE_ATTR_RW(enable);
+static ssize_t ctmid_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return scnprintf(buf, PAGE_SIZE, "%d\n", drvdata->ctidev.ctm_id); +} +static DEVICE_ATTR_RO(ctmid); + /* attribute and group sysfs tables. */ static struct attribute *coresight_cti_attrs[] = { &dev_attr_enable.attr, + &dev_attr_ctmid.attr, + NULL, +}; + +/* register based attributes */ + +/* macro to access RO registers with power check only (no enable check). */ +#define coresight_cti_reg(name, offset) \ +static ssize_t name##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \ + u32 val = 0; \ + pm_runtime_get_sync(dev->parent); \ + spin_lock(&drvdata->spinlock); \ + if (drvdata->config.hw_powered) \ + val = readl_relaxed(drvdata->base + offset); \ + spin_unlock(&drvdata->spinlock); \ + pm_runtime_put_sync(dev->parent); \ + return scnprintf(buf, PAGE_SIZE, "0x%x\n", val); \ +} \ +static DEVICE_ATTR_RO(name) + +/* coresight management registers */ +coresight_cti_reg(devaff0, CTIDEVAFF0); +coresight_cti_reg(devaff1, CTIDEVAFF1); +coresight_cti_reg(authstatus, CORESIGHT_AUTHSTATUS); +coresight_cti_reg(devarch, CORESIGHT_DEVARCH); +coresight_cti_reg(devid, CORESIGHT_DEVID); +coresight_cti_reg(devtype, CORESIGHT_DEVTYPE); +coresight_cti_reg(pidr0, CORESIGHT_PERIPHIDR0); +coresight_cti_reg(pidr1, CORESIGHT_PERIPHIDR1); +coresight_cti_reg(pidr2, CORESIGHT_PERIPHIDR2); +coresight_cti_reg(pidr3, CORESIGHT_PERIPHIDR3); +coresight_cti_reg(pidr4, CORESIGHT_PERIPHIDR4); + +static struct attribute *coresight_cti_mgmt_attrs[] = { + &dev_attr_devaff0.attr, + &dev_attr_devaff1.attr, + &dev_attr_authstatus.attr, + &dev_attr_devarch.attr, + &dev_attr_devid.attr, + &dev_attr_devtype.attr, + &dev_attr_pidr0.attr, + &dev_attr_pidr1.attr, + &dev_attr_pidr2.attr, + &dev_attr_pidr3.attr, + &dev_attr_pidr4.attr, NULL, };
@@ -66,7 +123,13 @@ static const struct attribute_group coresight_cti_group = { .attrs = coresight_cti_attrs, };
+static const struct attribute_group coresight_cti_mgmt_group = { + .attrs = coresight_cti_mgmt_attrs, + .name = "mgmt", +}; + const struct attribute_group *coresight_cti_groups[] = { &coresight_cti_group, + &coresight_cti_mgmt_group, NULL, }; diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index 82e563cdc879..aba6b789c969 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -22,6 +22,7 @@ #define CORESIGHT_CLAIMCLR 0xfa4 #define CORESIGHT_LAR 0xfb0 #define CORESIGHT_LSR 0xfb4 +#define CORESIGHT_DEVARCH 0xfbc #define CORESIGHT_AUTHSTATUS 0xfb8 #define CORESIGHT_DEVID 0xfc8 #define CORESIGHT_DEVTYPE 0xfcc
On Mon, Aug 19, 2019 at 10:13:48PM +0100, Mike Leach wrote:
Adds sysfs access to the coresight management registers.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-cti-sysfs.c | 67 ++++++++++++++++++- drivers/hwtracing/coresight/coresight-priv.h | 1 + 2 files changed, 66 insertions(+), 2 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index a832b8c6b866..20a9b30c9755 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -34,8 +34,7 @@ static ssize_t enable_show(struct device *dev, return size; } -static ssize_t enable_store(struct device *dev,
struct device_attribute *attr,
+static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
Redundant change?
The rest code in this patch looks good to me.
Thanks, Leo Yan
const char *buf, size_t size)
{ int ret = 0; @@ -56,9 +55,67 @@ static ssize_t enable_store(struct device *dev, } static DEVICE_ATTR_RW(enable); +static ssize_t ctmid_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- return scnprintf(buf, PAGE_SIZE, "%d\n", drvdata->ctidev.ctm_id);
+} +static DEVICE_ATTR_RO(ctmid);
/* attribute and group sysfs tables. */ static struct attribute *coresight_cti_attrs[] = { &dev_attr_enable.attr,
- &dev_attr_ctmid.attr,
- NULL,
+};
+/* register based attributes */
+/* macro to access RO registers with power check only (no enable check). */ +#define coresight_cti_reg(name, offset) \ +static ssize_t name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
+{ \
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \
- u32 val = 0; \
- pm_runtime_get_sync(dev->parent); \
- spin_lock(&drvdata->spinlock); \
- if (drvdata->config.hw_powered) \
val = readl_relaxed(drvdata->base + offset); \
- spin_unlock(&drvdata->spinlock); \
- pm_runtime_put_sync(dev->parent); \
- return scnprintf(buf, PAGE_SIZE, "0x%x\n", val); \
+} \ +static DEVICE_ATTR_RO(name)
+/* coresight management registers */ +coresight_cti_reg(devaff0, CTIDEVAFF0); +coresight_cti_reg(devaff1, CTIDEVAFF1); +coresight_cti_reg(authstatus, CORESIGHT_AUTHSTATUS); +coresight_cti_reg(devarch, CORESIGHT_DEVARCH); +coresight_cti_reg(devid, CORESIGHT_DEVID); +coresight_cti_reg(devtype, CORESIGHT_DEVTYPE); +coresight_cti_reg(pidr0, CORESIGHT_PERIPHIDR0); +coresight_cti_reg(pidr1, CORESIGHT_PERIPHIDR1); +coresight_cti_reg(pidr2, CORESIGHT_PERIPHIDR2); +coresight_cti_reg(pidr3, CORESIGHT_PERIPHIDR3); +coresight_cti_reg(pidr4, CORESIGHT_PERIPHIDR4);
+static struct attribute *coresight_cti_mgmt_attrs[] = {
- &dev_attr_devaff0.attr,
- &dev_attr_devaff1.attr,
- &dev_attr_authstatus.attr,
- &dev_attr_devarch.attr,
- &dev_attr_devid.attr,
- &dev_attr_devtype.attr,
- &dev_attr_pidr0.attr,
- &dev_attr_pidr1.attr,
- &dev_attr_pidr2.attr,
- &dev_attr_pidr3.attr,
- &dev_attr_pidr4.attr, NULL,
}; @@ -66,7 +123,13 @@ static const struct attribute_group coresight_cti_group = { .attrs = coresight_cti_attrs, }; +static const struct attribute_group coresight_cti_mgmt_group = {
- .attrs = coresight_cti_mgmt_attrs,
- .name = "mgmt",
+};
const struct attribute_group *coresight_cti_groups[] = { &coresight_cti_group,
- &coresight_cti_mgmt_group, NULL,
}; diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index 82e563cdc879..aba6b789c969 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -22,6 +22,7 @@ #define CORESIGHT_CLAIMCLR 0xfa4 #define CORESIGHT_LAR 0xfb0 #define CORESIGHT_LSR 0xfb4 +#define CORESIGHT_DEVARCH 0xfbc #define CORESIGHT_AUTHSTATUS 0xfb8 #define CORESIGHT_DEVID 0xfc8
#define CORESIGHT_DEVTYPE 0xfcc
2.17.1
CoreSight mailing list CoreSight@lists.linaro.org https://lists.linaro.org/mailman/listinfo/coresight
Hi Leo,
On Mon, 2 Sep 2019 at 08:44, Leo Yan leo.yan@linaro.org wrote:
On Mon, Aug 19, 2019 at 10:13:48PM +0100, Mike Leach wrote:
Adds sysfs access to the coresight management registers.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-cti-sysfs.c | 67 ++++++++++++++++++- drivers/hwtracing/coresight/coresight-priv.h | 1 + 2 files changed, 66 insertions(+), 2 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index a832b8c6b866..20a9b30c9755 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -34,8 +34,7 @@ static ssize_t enable_show(struct device *dev, return size; }
-static ssize_t enable_store(struct device *dev,
struct device_attribute *attr,
+static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
Redundant change?
The rest code in this patch looks good to me.
Fixup for function parameter alignment mentioned in v3 comments
Thanks
Mike
Thanks, Leo Yan
const char *buf, size_t size)
{ int ret = 0; @@ -56,9 +55,67 @@ static ssize_t enable_store(struct device *dev, } static DEVICE_ATTR_RW(enable);
+static ssize_t ctmid_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
return scnprintf(buf, PAGE_SIZE, "%d\n", drvdata->ctidev.ctm_id);
+} +static DEVICE_ATTR_RO(ctmid);
/* attribute and group sysfs tables. */ static struct attribute *coresight_cti_attrs[] = { &dev_attr_enable.attr,
&dev_attr_ctmid.attr,
NULL,
+};
+/* register based attributes */
+/* macro to access RO registers with power check only (no enable check). */ +#define coresight_cti_reg(name, offset) \ +static ssize_t name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
+{ \
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \
u32 val = 0; \
pm_runtime_get_sync(dev->parent); \
spin_lock(&drvdata->spinlock); \
if (drvdata->config.hw_powered) \
val = readl_relaxed(drvdata->base + offset); \
spin_unlock(&drvdata->spinlock); \
pm_runtime_put_sync(dev->parent); \
return scnprintf(buf, PAGE_SIZE, "0x%x\n", val); \
+} \ +static DEVICE_ATTR_RO(name)
+/* coresight management registers */ +coresight_cti_reg(devaff0, CTIDEVAFF0); +coresight_cti_reg(devaff1, CTIDEVAFF1); +coresight_cti_reg(authstatus, CORESIGHT_AUTHSTATUS); +coresight_cti_reg(devarch, CORESIGHT_DEVARCH); +coresight_cti_reg(devid, CORESIGHT_DEVID); +coresight_cti_reg(devtype, CORESIGHT_DEVTYPE); +coresight_cti_reg(pidr0, CORESIGHT_PERIPHIDR0); +coresight_cti_reg(pidr1, CORESIGHT_PERIPHIDR1); +coresight_cti_reg(pidr2, CORESIGHT_PERIPHIDR2); +coresight_cti_reg(pidr3, CORESIGHT_PERIPHIDR3); +coresight_cti_reg(pidr4, CORESIGHT_PERIPHIDR4);
+static struct attribute *coresight_cti_mgmt_attrs[] = {
&dev_attr_devaff0.attr,
&dev_attr_devaff1.attr,
&dev_attr_authstatus.attr,
&dev_attr_devarch.attr,
&dev_attr_devid.attr,
&dev_attr_devtype.attr,
&dev_attr_pidr0.attr,
&dev_attr_pidr1.attr,
&dev_attr_pidr2.attr,
&dev_attr_pidr3.attr,
&dev_attr_pidr4.attr, NULL,
};
@@ -66,7 +123,13 @@ static const struct attribute_group coresight_cti_group = { .attrs = coresight_cti_attrs, };
+static const struct attribute_group coresight_cti_mgmt_group = {
.attrs = coresight_cti_mgmt_attrs,
.name = "mgmt",
+};
const struct attribute_group *coresight_cti_groups[] = { &coresight_cti_group,
&coresight_cti_mgmt_group, NULL,
}; diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index 82e563cdc879..aba6b789c969 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -22,6 +22,7 @@ #define CORESIGHT_CLAIMCLR 0xfa4 #define CORESIGHT_LAR 0xfb0 #define CORESIGHT_LSR 0xfb4 +#define CORESIGHT_DEVARCH 0xfbc #define CORESIGHT_AUTHSTATUS 0xfb8 #define CORESIGHT_DEVID 0xfc8
#define CORESIGHT_DEVTYPE 0xfcc
2.17.1
CoreSight mailing list CoreSight@lists.linaro.org https://lists.linaro.org/mailman/listinfo/coresight
On Mon, Sep 02, 2019 at 02:22:47PM +0100, Mike Leach wrote:
Hi Leo,
On Mon, 2 Sep 2019 at 08:44, Leo Yan leo.yan@linaro.org wrote:
On Mon, Aug 19, 2019 at 10:13:48PM +0100, Mike Leach wrote:
Adds sysfs access to the coresight management registers.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-cti-sysfs.c | 67 ++++++++++++++++++- drivers/hwtracing/coresight/coresight-priv.h | 1 + 2 files changed, 66 insertions(+), 2 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index a832b8c6b866..20a9b30c9755 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -34,8 +34,7 @@ static ssize_t enable_show(struct device *dev, return size; }
-static ssize_t enable_store(struct device *dev,
struct device_attribute *attr,
+static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
Redundant change?
The rest code in this patch looks good to me.
Fixup for function parameter alignment mentioned in v3 comments
Ah, if so it's better to fixup in the first place in patch 01.
Thanks, Leo Yan
On Mon, Sep 02, 2019 at 02:22:47PM +0100, Mike Leach wrote:
Hi Leo,
On Mon, 2 Sep 2019 at 08:44, Leo Yan leo.yan@linaro.org wrote:
On Mon, Aug 19, 2019 at 10:13:48PM +0100, Mike Leach wrote:
Adds sysfs access to the coresight management registers.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-cti-sysfs.c | 67 ++++++++++++++++++- drivers/hwtracing/coresight/coresight-priv.h | 1 + 2 files changed, 66 insertions(+), 2 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index a832b8c6b866..20a9b30c9755 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -34,8 +34,7 @@ static ssize_t enable_show(struct device *dev, return size; }
-static ssize_t enable_store(struct device *dev,
struct device_attribute *attr,
+static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
Redundant change?
The rest code in this patch looks good to me.
Fixup for function parameter alignment mentioned in v3 comments
In this set the alignment for function enable_store() in patch 1/15 is correct and doesn't need modification.
Thanks
Mike
Thanks, Leo Yan
const char *buf, size_t size)
{ int ret = 0; @@ -56,9 +55,67 @@ static ssize_t enable_store(struct device *dev, } static DEVICE_ATTR_RW(enable);
+static ssize_t ctmid_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
return scnprintf(buf, PAGE_SIZE, "%d\n", drvdata->ctidev.ctm_id);
+} +static DEVICE_ATTR_RO(ctmid);
/* attribute and group sysfs tables. */ static struct attribute *coresight_cti_attrs[] = { &dev_attr_enable.attr,
&dev_attr_ctmid.attr,
NULL,
+};
+/* register based attributes */
+/* macro to access RO registers with power check only (no enable check). */ +#define coresight_cti_reg(name, offset) \ +static ssize_t name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
+{ \
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \
u32 val = 0; \
pm_runtime_get_sync(dev->parent); \
spin_lock(&drvdata->spinlock); \
if (drvdata->config.hw_powered) \
val = readl_relaxed(drvdata->base + offset); \
spin_unlock(&drvdata->spinlock); \
pm_runtime_put_sync(dev->parent); \
return scnprintf(buf, PAGE_SIZE, "0x%x\n", val); \
+} \ +static DEVICE_ATTR_RO(name)
+/* coresight management registers */ +coresight_cti_reg(devaff0, CTIDEVAFF0); +coresight_cti_reg(devaff1, CTIDEVAFF1); +coresight_cti_reg(authstatus, CORESIGHT_AUTHSTATUS); +coresight_cti_reg(devarch, CORESIGHT_DEVARCH); +coresight_cti_reg(devid, CORESIGHT_DEVID); +coresight_cti_reg(devtype, CORESIGHT_DEVTYPE); +coresight_cti_reg(pidr0, CORESIGHT_PERIPHIDR0); +coresight_cti_reg(pidr1, CORESIGHT_PERIPHIDR1); +coresight_cti_reg(pidr2, CORESIGHT_PERIPHIDR2); +coresight_cti_reg(pidr3, CORESIGHT_PERIPHIDR3); +coresight_cti_reg(pidr4, CORESIGHT_PERIPHIDR4);
+static struct attribute *coresight_cti_mgmt_attrs[] = {
&dev_attr_devaff0.attr,
&dev_attr_devaff1.attr,
&dev_attr_authstatus.attr,
&dev_attr_devarch.attr,
&dev_attr_devid.attr,
&dev_attr_devtype.attr,
&dev_attr_pidr0.attr,
&dev_attr_pidr1.attr,
&dev_attr_pidr2.attr,
&dev_attr_pidr3.attr,
&dev_attr_pidr4.attr, NULL,
};
@@ -66,7 +123,13 @@ static const struct attribute_group coresight_cti_group = { .attrs = coresight_cti_attrs, };
+static const struct attribute_group coresight_cti_mgmt_group = {
.attrs = coresight_cti_mgmt_attrs,
.name = "mgmt",
+};
const struct attribute_group *coresight_cti_groups[] = { &coresight_cti_group,
&coresight_cti_mgmt_group, NULL,
}; diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index 82e563cdc879..aba6b789c969 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -22,6 +22,7 @@ #define CORESIGHT_CLAIMCLR 0xfa4 #define CORESIGHT_LAR 0xfb0 #define CORESIGHT_LSR 0xfb4 +#define CORESIGHT_DEVARCH 0xfbc #define CORESIGHT_AUTHSTATUS 0xfb8 #define CORESIGHT_DEVID 0xfc8
#define CORESIGHT_DEVTYPE 0xfcc
2.17.1
CoreSight mailing list CoreSight@lists.linaro.org https://lists.linaro.org/mailman/listinfo/coresight
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
On Mon, Aug 19, 2019 at 10:13:48PM +0100, Mike Leach wrote:
Adds sysfs access to the coresight management registers.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-cti-sysfs.c | 67 ++++++++++++++++++- drivers/hwtracing/coresight/coresight-priv.h | 1 + 2 files changed, 66 insertions(+), 2 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index a832b8c6b866..20a9b30c9755 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -34,8 +34,7 @@ static ssize_t enable_show(struct device *dev, return size; } -static ssize_t enable_store(struct device *dev,
struct device_attribute *attr,
+static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
This line doesn't bring anything to the patch - please revert.
const char *buf, size_t size)
{ int ret = 0; @@ -56,9 +55,67 @@ static ssize_t enable_store(struct device *dev, } static DEVICE_ATTR_RW(enable); +static ssize_t ctmid_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- return scnprintf(buf, PAGE_SIZE, "%d\n", drvdata->ctidev.ctm_id);
+} +static DEVICE_ATTR_RO(ctmid);
/* attribute and group sysfs tables. */ static struct attribute *coresight_cti_attrs[] = { &dev_attr_enable.attr,
- &dev_attr_ctmid.attr,
- NULL,
+};
+/* register based attributes */
+/* macro to access RO registers with power check only (no enable check). */ +#define coresight_cti_reg(name, offset) \ +static ssize_t name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
+{ \
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \
- u32 val = 0; \
- pm_runtime_get_sync(dev->parent); \
- spin_lock(&drvdata->spinlock); \
- if (drvdata->config.hw_powered) \
val = readl_relaxed(drvdata->base + offset); \
- spin_unlock(&drvdata->spinlock); \
- pm_runtime_put_sync(dev->parent); \
- return scnprintf(buf, PAGE_SIZE, "0x%x\n", val); \
+} \ +static DEVICE_ATTR_RO(name)
+/* coresight management registers */ +coresight_cti_reg(devaff0, CTIDEVAFF0); +coresight_cti_reg(devaff1, CTIDEVAFF1); +coresight_cti_reg(authstatus, CORESIGHT_AUTHSTATUS); +coresight_cti_reg(devarch, CORESIGHT_DEVARCH); +coresight_cti_reg(devid, CORESIGHT_DEVID); +coresight_cti_reg(devtype, CORESIGHT_DEVTYPE); +coresight_cti_reg(pidr0, CORESIGHT_PERIPHIDR0); +coresight_cti_reg(pidr1, CORESIGHT_PERIPHIDR1); +coresight_cti_reg(pidr2, CORESIGHT_PERIPHIDR2); +coresight_cti_reg(pidr3, CORESIGHT_PERIPHIDR3); +coresight_cti_reg(pidr4, CORESIGHT_PERIPHIDR4);
+static struct attribute *coresight_cti_mgmt_attrs[] = {
- &dev_attr_devaff0.attr,
- &dev_attr_devaff1.attr,
- &dev_attr_authstatus.attr,
- &dev_attr_devarch.attr,
- &dev_attr_devid.attr,
- &dev_attr_devtype.attr,
- &dev_attr_pidr0.attr,
- &dev_attr_pidr1.attr,
- &dev_attr_pidr2.attr,
- &dev_attr_pidr3.attr,
- &dev_attr_pidr4.attr, NULL,
}; @@ -66,7 +123,13 @@ static const struct attribute_group coresight_cti_group = { .attrs = coresight_cti_attrs, }; +static const struct attribute_group coresight_cti_mgmt_group = {
- .attrs = coresight_cti_mgmt_attrs,
- .name = "mgmt",
+};
const struct attribute_group *coresight_cti_groups[] = { &coresight_cti_group,
- &coresight_cti_mgmt_group, NULL,
}; diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index 82e563cdc879..aba6b789c969 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -22,6 +22,7 @@ #define CORESIGHT_CLAIMCLR 0xfa4 #define CORESIGHT_LAR 0xfb0 #define CORESIGHT_LSR 0xfb4 +#define CORESIGHT_DEVARCH 0xfbc
With the above change:
Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org
#define CORESIGHT_AUTHSTATUS 0xfb8 #define CORESIGHT_DEVID 0xfc8
#define CORESIGHT_DEVTYPE 0xfcc
2.17.1
On 08/19/2019 10:13 PM, Mike Leach wrote:
Adds sysfs access to the coresight management registers.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-cti-sysfs.c | 67 ++++++++++++++++++- drivers/hwtracing/coresight/coresight-priv.h | 1 + 2 files changed, 66 insertions(+), 2 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index a832b8c6b866..20a9b30c9755 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -34,8 +34,7 @@ static ssize_t enable_show(struct device *dev, return size; } -static ssize_t enable_store(struct device *dev,
struct device_attribute *attr,
+static ssize_t enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int ret = 0;
Like Mathieu said, once you remove the spurious change above, feel free to add :
Reviewed-by: Suzuki K Poulose suzuki.poulose@arm.com
Adds in sysfs programming support for the CTI function register sets. Allows direct manipulation of channel / trigger association registers.
Signed-off-by: Mike Leach mike.leach@linaro.org --- .../hwtracing/coresight/coresight-cti-sysfs.c | 368 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.c | 19 + drivers/hwtracing/coresight/coresight-cti.h | 5 + 3 files changed, 392 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 20a9b30c9755..4055e392530d 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -119,6 +119,368 @@ static struct attribute *coresight_cti_mgmt_attrs[] = { NULL, };
+/* CTI low level programming registers */ + +/* + * Show a simple 32 bit value if enabled and powered. + * If inaccessible & pcached_val not NULL then show cached value. + */ +static ssize_t cti_reg32_show(struct device *dev, char *buf, + u32 *pcached_val, int reg_offset) +{ + u32 val = 0; + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cti_config *config = &drvdata->config; + + spin_lock(&drvdata->spinlock); + if ((reg_offset >= 0) && CTI_PWR_ENA(config)) { + CS_UNLOCK(drvdata->base); + val = readl_relaxed(drvdata->base + reg_offset); + if (pcached_val) + *pcached_val = val; + CS_LOCK(drvdata->base); + } else if (pcached_val) { + val = *pcached_val; + } + spin_unlock(&drvdata->spinlock); + return scnprintf(buf, PAGE_SIZE, "%#x\n", val); +} + +/* + * Store a simple 32 bit value. + * If pcached_val not NULL, then copy to here too, + * if reg_offset >= 0 then write through if enabled. + */ +static ssize_t cti_reg32_store(struct device *dev, const char *buf, + size_t size, u32 *pcached_val, int reg_offset) +{ + unsigned long val; + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cti_config *config = &drvdata->config; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + spin_lock(&drvdata->spinlock); + /* local store */ + if (pcached_val) + *pcached_val = (u32)val; + + /* write through if offset and enabled */ + if ((reg_offset >= 0) && CTI_PWR_ENA(config)) + cti_write_single_reg(drvdata, reg_offset, val); + spin_unlock(&drvdata->spinlock); + return size; +} + +/* Standard macro for simple rw cti config registers */ +#define cti_config_reg32_rw(name, cfgname, offset) \ +static ssize_t name##_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \ + return cti_reg32_show(dev, buf, \ + &drvdata->config.cfgname, offset); \ +} \ + \ +static ssize_t name##_store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t size) \ +{ \ + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \ + return cti_reg32_store(dev, buf, size, \ + &drvdata->config.cfgname, offset); \ +} \ +static DEVICE_ATTR_RW(name) + +static ssize_t inout_sel_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + u32 val; + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + + val = (u32)drvdata->config.ctiinout_sel; + return scnprintf(buf, PAGE_SIZE, "%d\n", val); +} + +static ssize_t inout_sel_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + unsigned long val; + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + if (val > (CTIINOUTEN_MAX-1)) + return -EINVAL; + + spin_lock(&drvdata->spinlock); + drvdata->config.ctiinout_sel = val; + spin_unlock(&drvdata->spinlock); + return size; +} +static DEVICE_ATTR_RW(inout_sel); + +static ssize_t inen_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + unsigned long val; + int index; + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + + spin_lock(&drvdata->spinlock); + index = drvdata->config.ctiinout_sel; + val = drvdata->config.ctiinen[index]; + spin_unlock(&drvdata->spinlock); + return scnprintf(buf, PAGE_SIZE, "INEN%d %#lx\n", index, val); +} + +static ssize_t inen_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + unsigned long val; + int index; + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cti_config *config = &drvdata->config; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + spin_lock(&drvdata->spinlock); + index = config->ctiinout_sel; + config->ctiinen[index] = val; + + /* write through if enabled */ + if (CTI_PWR_ENA(config)) + cti_write_single_reg(drvdata, CTIINEN(index), val); + spin_unlock(&drvdata->spinlock); + return size; +} +static DEVICE_ATTR_RW(inen); + +static ssize_t outen_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + unsigned long val; + int index; + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + + spin_lock(&drvdata->spinlock); + index = drvdata->config.ctiinout_sel; + val = drvdata->config.ctiouten[index]; + spin_unlock(&drvdata->spinlock); + return scnprintf(buf, PAGE_SIZE, "OUTEN%d %#lx\n", index, val); +} + +static ssize_t outen_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + unsigned long val; + int index; + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cti_config *config = &drvdata->config; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + spin_lock(&drvdata->spinlock); + index = config->ctiinout_sel; + config->ctiouten[index] = val; + + /* write through if enabled */ + if (CTI_PWR_ENA(config)) + cti_write_single_reg(drvdata, CTIOUTEN(index), val); + spin_unlock(&drvdata->spinlock); + return size; +} +static DEVICE_ATTR_RW(outen); + +static ssize_t intack_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + cti_write_intack(dev, val); + return size; +} +static DEVICE_ATTR_WO(intack); + +cti_config_reg32_rw(gate, ctigate, CTIGATE); +cti_config_reg32_rw(asicctl, asicctl, ASICCTL); +cti_config_reg32_rw(appset, ctiappset, CTIAPPSET); + +static ssize_t appclear_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + unsigned long val; + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cti_config *config = &drvdata->config; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + spin_lock(&drvdata->spinlock); + + /* a 1'b1 in appclr clears down the same bit in appset*/ + config->ctiappset &= ~val; + + /* write through if enabled */ + if (CTI_PWR_ENA(config)) + cti_write_single_reg(drvdata, CTIAPPCLEAR, val); + spin_unlock(&drvdata->spinlock); + return size; +} +static DEVICE_ATTR_WO(appclear); + +static ssize_t apppulse_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + unsigned long val; + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cti_config *config = &drvdata->config; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + spin_lock(&drvdata->spinlock); + + /* + * a 1'b1 in apppulse sets then clears the bit, + * effectively clears down the same bit in appset + */ + config->ctiappset &= ~val; + + /* write through if enabled */ + if (CTI_PWR_ENA(config)) + cti_write_single_reg(drvdata, CTIAPPPULSE, val); + spin_unlock(&drvdata->spinlock); + return size; +} +static DEVICE_ATTR_WO(apppulse); + +coresight_cti_reg(triginstatus, CTITRIGINSTATUS); +coresight_cti_reg(trigoutstatus, CTITRIGOUTSTATUS); +coresight_cti_reg(chinstatus, CTICHINSTATUS); +coresight_cti_reg(choutstatus, CTICHOUTSTATUS); + +/* + * #define CTI_DEBUG_INTEGRATION_CTRL to enable the access to the integration + * control registers. Normally only used to investigate connection data. + */ +/* #define CTI_DEBUG_INTEGRATION_CTRL */ + +#ifdef CTI_DEBUG_INTEGRATION_CTRL + +/* macro to access RW registers with power check only (no enable check). */ +#define coresight_cti_reg_rw(name, offset) \ +static ssize_t name##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \ + u32 val = 0; \ + pm_runtime_get_sync(dev->parent); \ + spin_lock(&drvdata->spinlock); \ + if (drvdata->config.hw_powered) \ + val = readl_relaxed(drvdata->base + offset); \ + spin_unlock(&drvdata->spinlock); \ + pm_runtime_put_sync(dev->parent); \ + return scnprintf(buf, PAGE_SIZE, "0x%x\n", val); \ +} \ + \ +static ssize_t name##_store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t size) \ +{ \ + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \ + unsigned long val = 0; \ + if (kstrtoul(buf, 0, &val)) \ + return -EINVAL; \ + \ + pm_runtime_get_sync(dev->parent); \ + spin_lock(&drvdata->spinlock); \ + if (drvdata->config.hw_powered) \ + cti_write_single_reg(drvdata, reg_offset, val); \ + spin_unlock(&drvdata->spinlock); \ + pm_runtime_put_sync(dev->parent); \ + return size; \ +} \ +static DEVICE_ATTR_RW(name) + +/* macro to access WO registers with power check only (no enable check). */ +#define coresight_cti_reg_wo(name, offset) \ +static ssize_t name##_store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t size) \ +{ \ + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \ + unsigned long val = 0; \ + if (kstrtoul(buf, 0, &val)) \ + return -EINVAL; \ + \ + pm_runtime_get_sync(dev->parent); \ + spin_lock(&drvdata->spinlock); \ + if (drvdata->config.hw_powered) \ + cti_write_single_reg(drvdata, reg_offset, val); \ + spin_unlock(&drvdata->spinlock); \ + pm_runtime_put_sync(dev->parent); \ + return size; \ +} \ +static DEVICE_ATTR_WO(name) + +coresight_cti_reg_rw(itchout, ITCHOUT); +coresight_cti_reg_rw(ittrigout, ITTRIGOUT); +coresight_cti_reg_rw(itctrl, CORESIGHT_ITCTRL); +coresight_cti_reg_wo(itchinack, ITCHINACK); +coresight_cti_reg_wo(ittriginack, ITTRIGINACK); +coresight_cti_reg(ittrigin, ITTRIGIN); +coresight_cti_reg(itchin, ITCHIN); +coresight_cti_reg(itchoutack, ITCHOUTACK); +coresight_cti_reg(ittrigoutack, ITTRIGOUTACK); + +#endif /* CTI_DEBUG_INTEGRATION_CTRL */ + +static struct attribute *coresight_cti_regs_attrs[] = { + &dev_attr_inout_sel.attr, + &dev_attr_inen.attr, + &dev_attr_outen.attr, + &dev_attr_gate.attr, + &dev_attr_asicctl.attr, + &dev_attr_intack.attr, + &dev_attr_appset.attr, + &dev_attr_appclear.attr, + &dev_attr_apppulse.attr, + &dev_attr_triginstatus.attr, + &dev_attr_trigoutstatus.attr, + &dev_attr_chinstatus.attr, + &dev_attr_choutstatus.attr, +#ifdef CTI_DEBUG_INTEGRATION_CTRL + &dev_attr_itctrl.attr, + &dev_attr_ittrigin.attr, + &dev_attr_itchin.attr, + &dev_attr_ittrigout.attr, + &dev_attr_itchout.attr, + &dev_attr_itchoutack.attr, + &dev_attr_ittrigoutack.attr, + &dev_attr_ittriginack.attr, + &dev_attr_itchinack.attr, +#endif + NULL, +}; + +/* sysfs groups */ static const struct attribute_group coresight_cti_group = { .attrs = coresight_cti_attrs, }; @@ -128,8 +490,14 @@ static const struct attribute_group coresight_cti_mgmt_group = { .name = "mgmt", };
+static const struct attribute_group coresight_cti_regs_group = { + .attrs = coresight_cti_regs_attrs, + .name = "regs", +}; + const struct attribute_group *coresight_cti_groups[] = { &coresight_cti_group, &coresight_cti_mgmt_group, + &coresight_cti_regs_group, NULL, }; diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index b56d9a02c4b4..0368fa7c6179 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -151,6 +151,25 @@ static int cti_disable_hw(struct cti_drvdata *drvdata, bool update_refcount) return 0; }
+void cti_write_single_reg(struct cti_drvdata *drvdata, int offset, u32 value) +{ + CS_UNLOCK(drvdata->base); + writel_relaxed(value, drvdata->base + offset); + CS_LOCK(drvdata->base); +} + +void cti_write_intack(struct device *dev, u32 ackval) +{ + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cti_config *config = &drvdata->config; + + spin_lock(&drvdata->spinlock); + /* write if enabled */ + if (CTI_PWR_ENA(config)) + cti_write_single_reg(drvdata, CTIINTACK, ackval); + spin_unlock(&drvdata->spinlock); +} + /* * Look at the HW DEVID register for some of the HW settings. * DEVID[15:8] - max number of in / out triggers. diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index 717035a9aa72..db8667a2691c 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -186,7 +186,12 @@ struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs, int out_sigs); int cti_enable(struct coresight_device *csdev); int cti_disable(struct coresight_device *csdev); +void cti_write_intack(struct device *dev, u32 ackval); +void cti_write_single_reg(struct cti_drvdata *drvdata, int offset, u32 value); struct coresight_platform_data * coresight_cti_get_platform_data(struct device *dev);
+/* cti powered and enabled */ +#define CTI_PWR_ENA(p_cfg) (p_cfg->hw_enabled && p_cfg->hw_powered) + #endif /* _CORESIGHT_CORESIGHT_CTI_H */
On Mon, Aug 19, 2019 at 10:13:49PM +0100, Mike Leach wrote:
Adds in sysfs programming support for the CTI function register sets. Allows direct manipulation of channel / trigger association registers.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-cti-sysfs.c | 368 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.c | 19 + drivers/hwtracing/coresight/coresight-cti.h | 5 + 3 files changed, 392 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 20a9b30c9755..4055e392530d 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -119,6 +119,368 @@ static struct attribute *coresight_cti_mgmt_attrs[] = { NULL, }; +/* CTI low level programming registers */
+/*
- Show a simple 32 bit value if enabled and powered.
- If inaccessible & pcached_val not NULL then show cached value.
- */
+static ssize_t cti_reg32_show(struct device *dev, char *buf,
u32 *pcached_val, int reg_offset)
+{
- u32 val = 0;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
- if ((reg_offset >= 0) && CTI_PWR_ENA(config)) {
CS_UNLOCK(drvdata->base);
val = readl_relaxed(drvdata->base + reg_offset);
if (pcached_val)
*pcached_val = val;
CS_LOCK(drvdata->base);
- } else if (pcached_val) {
val = *pcached_val;
- }
- spin_unlock(&drvdata->spinlock);
- return scnprintf(buf, PAGE_SIZE, "%#x\n", val);
+}
+/*
- Store a simple 32 bit value.
- If pcached_val not NULL, then copy to here too,
- if reg_offset >= 0 then write through if enabled.
- */
+static ssize_t cti_reg32_store(struct device *dev, const char *buf,
size_t size, u32 *pcached_val, int reg_offset)
+{
- unsigned long val;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *config = &drvdata->config;
- if (kstrtoul(buf, 0, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
- /* local store */
- if (pcached_val)
*pcached_val = (u32)val;
- /* write through if offset and enabled */
- if ((reg_offset >= 0) && CTI_PWR_ENA(config))
cti_write_single_reg(drvdata, reg_offset, val);
- spin_unlock(&drvdata->spinlock);
- return size;
+}
+/* Standard macro for simple rw cti config registers */ +#define cti_config_reg32_rw(name, cfgname, offset) \ +static ssize_t name##_show(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
+{ \
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \
- return cti_reg32_show(dev, buf, \
&drvdata->config.cfgname, offset); \
+} \
\
+static ssize_t name##_store(struct device *dev, \
struct device_attribute *attr, \
const char *buf, size_t size) \
+{ \
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \
- return cti_reg32_store(dev, buf, size, \
&drvdata->config.cfgname, offset); \
+} \ +static DEVICE_ATTR_RW(name)
+static ssize_t inout_sel_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- u32 val;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- val = (u32)drvdata->config.ctiinout_sel;
- return scnprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+static ssize_t inout_sel_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- unsigned long val;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- if (kstrtoul(buf, 0, &val))
return -EINVAL;
- if (val > (CTIINOUTEN_MAX-1))
s/"CTIINOUTEN_MAX-1"/"CTIINOUTEN_MAX - 1"
With that: Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org
return -EINVAL;
- spin_lock(&drvdata->spinlock);
- drvdata->config.ctiinout_sel = val;
- spin_unlock(&drvdata->spinlock);
- return size;
+} +static DEVICE_ATTR_RW(inout_sel);
+static ssize_t inen_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- unsigned long val;
- int index;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- spin_lock(&drvdata->spinlock);
- index = drvdata->config.ctiinout_sel;
- val = drvdata->config.ctiinen[index];
- spin_unlock(&drvdata->spinlock);
- return scnprintf(buf, PAGE_SIZE, "INEN%d %#lx\n", index, val);
+}
+static ssize_t inen_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- unsigned long val;
- int index;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *config = &drvdata->config;
- if (kstrtoul(buf, 0, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
- index = config->ctiinout_sel;
- config->ctiinen[index] = val;
- /* write through if enabled */
- if (CTI_PWR_ENA(config))
cti_write_single_reg(drvdata, CTIINEN(index), val);
- spin_unlock(&drvdata->spinlock);
- return size;
+} +static DEVICE_ATTR_RW(inen);
+static ssize_t outen_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- unsigned long val;
- int index;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- spin_lock(&drvdata->spinlock);
- index = drvdata->config.ctiinout_sel;
- val = drvdata->config.ctiouten[index];
- spin_unlock(&drvdata->spinlock);
- return scnprintf(buf, PAGE_SIZE, "OUTEN%d %#lx\n", index, val);
+}
+static ssize_t outen_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- unsigned long val;
- int index;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *config = &drvdata->config;
- if (kstrtoul(buf, 0, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
- index = config->ctiinout_sel;
- config->ctiouten[index] = val;
- /* write through if enabled */
- if (CTI_PWR_ENA(config))
cti_write_single_reg(drvdata, CTIOUTEN(index), val);
- spin_unlock(&drvdata->spinlock);
- return size;
+} +static DEVICE_ATTR_RW(outen);
+static ssize_t intack_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- unsigned long val;
- if (kstrtoul(buf, 0, &val))
return -EINVAL;
- cti_write_intack(dev, val);
- return size;
+} +static DEVICE_ATTR_WO(intack);
+cti_config_reg32_rw(gate, ctigate, CTIGATE); +cti_config_reg32_rw(asicctl, asicctl, ASICCTL); +cti_config_reg32_rw(appset, ctiappset, CTIAPPSET);
+static ssize_t appclear_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- unsigned long val;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *config = &drvdata->config;
- if (kstrtoul(buf, 0, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
- /* a 1'b1 in appclr clears down the same bit in appset*/
- config->ctiappset &= ~val;
- /* write through if enabled */
- if (CTI_PWR_ENA(config))
cti_write_single_reg(drvdata, CTIAPPCLEAR, val);
- spin_unlock(&drvdata->spinlock);
- return size;
+} +static DEVICE_ATTR_WO(appclear);
+static ssize_t apppulse_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- unsigned long val;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *config = &drvdata->config;
- if (kstrtoul(buf, 0, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
- /*
* a 1'b1 in apppulse sets then clears the bit,
* effectively clears down the same bit in appset
*/
- config->ctiappset &= ~val;
- /* write through if enabled */
- if (CTI_PWR_ENA(config))
cti_write_single_reg(drvdata, CTIAPPPULSE, val);
- spin_unlock(&drvdata->spinlock);
- return size;
+} +static DEVICE_ATTR_WO(apppulse);
+coresight_cti_reg(triginstatus, CTITRIGINSTATUS); +coresight_cti_reg(trigoutstatus, CTITRIGOUTSTATUS); +coresight_cti_reg(chinstatus, CTICHINSTATUS); +coresight_cti_reg(choutstatus, CTICHOUTSTATUS);
+/*
- #define CTI_DEBUG_INTEGRATION_CTRL to enable the access to the integration
- control registers. Normally only used to investigate connection data.
- */
+/* #define CTI_DEBUG_INTEGRATION_CTRL */
+#ifdef CTI_DEBUG_INTEGRATION_CTRL
+/* macro to access RW registers with power check only (no enable check). */ +#define coresight_cti_reg_rw(name, offset) \ +static ssize_t name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
+{ \
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \
- u32 val = 0; \
- pm_runtime_get_sync(dev->parent); \
- spin_lock(&drvdata->spinlock); \
- if (drvdata->config.hw_powered) \
val = readl_relaxed(drvdata->base + offset); \
- spin_unlock(&drvdata->spinlock); \
- pm_runtime_put_sync(dev->parent); \
- return scnprintf(buf, PAGE_SIZE, "0x%x\n", val); \
+} \
\
+static ssize_t name##_store(struct device *dev, \
struct device_attribute *attr, \
const char *buf, size_t size) \
+{ \
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \
- unsigned long val = 0; \
- if (kstrtoul(buf, 0, &val)) \
return -EINVAL; \
\
- pm_runtime_get_sync(dev->parent); \
- spin_lock(&drvdata->spinlock); \
- if (drvdata->config.hw_powered) \
cti_write_single_reg(drvdata, reg_offset, val); \
- spin_unlock(&drvdata->spinlock); \
- pm_runtime_put_sync(dev->parent); \
- return size; \
+} \ +static DEVICE_ATTR_RW(name)
+/* macro to access WO registers with power check only (no enable check). */ +#define coresight_cti_reg_wo(name, offset) \ +static ssize_t name##_store(struct device *dev, \
struct device_attribute *attr, \
const char *buf, size_t size) \
+{ \
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \
- unsigned long val = 0; \
- if (kstrtoul(buf, 0, &val)) \
return -EINVAL; \
\
- pm_runtime_get_sync(dev->parent); \
- spin_lock(&drvdata->spinlock); \
- if (drvdata->config.hw_powered) \
cti_write_single_reg(drvdata, reg_offset, val); \
- spin_unlock(&drvdata->spinlock); \
- pm_runtime_put_sync(dev->parent); \
- return size; \
+} \ +static DEVICE_ATTR_WO(name)
+coresight_cti_reg_rw(itchout, ITCHOUT); +coresight_cti_reg_rw(ittrigout, ITTRIGOUT); +coresight_cti_reg_rw(itctrl, CORESIGHT_ITCTRL); +coresight_cti_reg_wo(itchinack, ITCHINACK); +coresight_cti_reg_wo(ittriginack, ITTRIGINACK); +coresight_cti_reg(ittrigin, ITTRIGIN); +coresight_cti_reg(itchin, ITCHIN); +coresight_cti_reg(itchoutack, ITCHOUTACK); +coresight_cti_reg(ittrigoutack, ITTRIGOUTACK);
+#endif /* CTI_DEBUG_INTEGRATION_CTRL */
+static struct attribute *coresight_cti_regs_attrs[] = {
- &dev_attr_inout_sel.attr,
- &dev_attr_inen.attr,
- &dev_attr_outen.attr,
- &dev_attr_gate.attr,
- &dev_attr_asicctl.attr,
- &dev_attr_intack.attr,
- &dev_attr_appset.attr,
- &dev_attr_appclear.attr,
- &dev_attr_apppulse.attr,
- &dev_attr_triginstatus.attr,
- &dev_attr_trigoutstatus.attr,
- &dev_attr_chinstatus.attr,
- &dev_attr_choutstatus.attr,
+#ifdef CTI_DEBUG_INTEGRATION_CTRL
- &dev_attr_itctrl.attr,
- &dev_attr_ittrigin.attr,
- &dev_attr_itchin.attr,
- &dev_attr_ittrigout.attr,
- &dev_attr_itchout.attr,
- &dev_attr_itchoutack.attr,
- &dev_attr_ittrigoutack.attr,
- &dev_attr_ittriginack.attr,
- &dev_attr_itchinack.attr,
+#endif
- NULL,
+};
+/* sysfs groups */ static const struct attribute_group coresight_cti_group = { .attrs = coresight_cti_attrs, }; @@ -128,8 +490,14 @@ static const struct attribute_group coresight_cti_mgmt_group = { .name = "mgmt", }; +static const struct attribute_group coresight_cti_regs_group = {
- .attrs = coresight_cti_regs_attrs,
- .name = "regs",
+};
const struct attribute_group *coresight_cti_groups[] = { &coresight_cti_group, &coresight_cti_mgmt_group,
- &coresight_cti_regs_group, NULL,
}; diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index b56d9a02c4b4..0368fa7c6179 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -151,6 +151,25 @@ static int cti_disable_hw(struct cti_drvdata *drvdata, bool update_refcount) return 0; } +void cti_write_single_reg(struct cti_drvdata *drvdata, int offset, u32 value) +{
- CS_UNLOCK(drvdata->base);
- writel_relaxed(value, drvdata->base + offset);
- CS_LOCK(drvdata->base);
+}
+void cti_write_intack(struct device *dev, u32 ackval) +{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
- /* write if enabled */
- if (CTI_PWR_ENA(config))
cti_write_single_reg(drvdata, CTIINTACK, ackval);
- spin_unlock(&drvdata->spinlock);
+}
/*
- Look at the HW DEVID register for some of the HW settings.
- DEVID[15:8] - max number of in / out triggers.
diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index 717035a9aa72..db8667a2691c 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -186,7 +186,12 @@ struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs, int out_sigs); int cti_enable(struct coresight_device *csdev); int cti_disable(struct coresight_device *csdev); +void cti_write_intack(struct device *dev, u32 ackval); +void cti_write_single_reg(struct cti_drvdata *drvdata, int offset, u32 value); struct coresight_platform_data * coresight_cti_get_platform_data(struct device *dev); +/* cti powered and enabled */ +#define CTI_PWR_ENA(p_cfg) (p_cfg->hw_enabled && p_cfg->hw_powered)
#endif /* _CORESIGHT_CORESIGHT_CTI_H */
2.17.1
Adds a user API to allow programming of CTI by trigger ID and channel number. This will take the channel and trigger ID supplied by the user and program the appropriate register values.
Signed-off-by: Mike Leach mike.leach@linaro.org --- .../hwtracing/coresight/coresight-cti-sysfs.c | 355 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.c | 157 +++++++- drivers/hwtracing/coresight/coresight-cti.h | 34 ++ 3 files changed, 545 insertions(+), 1 deletion(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 4055e392530d..dbbfd1de58b3 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -480,6 +480,355 @@ static struct attribute *coresight_cti_regs_attrs[] = { NULL, };
+/* CTI channel x-trigger programming */ +static int +cti_trig_op_parse(struct device *dev, enum cti_chan_op op, + enum cti_trig_dir dir, const char *buf, size_t size) +{ + u32 chan_idx; + u32 trig_idx; + int items, err = size; + + /* extract chan idx and trigger idx */ + items = sscanf(buf, "%d %d", &chan_idx, &trig_idx); + if (items) { + err = cti_channel_trig_op(dev, op, dir, chan_idx, trig_idx); + if (!err) + err = size; + } else + err = -EINVAL; + return err; +} + +static ssize_t trigin_attach_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + return cti_trig_op_parse(dev, CTI_CHAN_ATTACH, CTI_TRIG_IN, + buf, size); +} +static DEVICE_ATTR_WO(trigin_attach); + +static ssize_t trigin_detach_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + return cti_trig_op_parse(dev, CTI_CHAN_DETACH, CTI_TRIG_IN, + buf, size); +} +static DEVICE_ATTR_WO(trigin_detach); + +static ssize_t trigout_attach_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + return cti_trig_op_parse(dev, CTI_CHAN_ATTACH, CTI_TRIG_OUT, + buf, size); +} +static DEVICE_ATTR_WO(trigout_attach); + +static ssize_t trigout_detach_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + return cti_trig_op_parse(dev, CTI_CHAN_DETACH, CTI_TRIG_OUT, + buf, size); +} +static DEVICE_ATTR_WO(trigout_detach); + + +static ssize_t gate_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int err = 0, channel = 0; + + if ((size >= 3) && (strncmp(buf, "all", 3) == 0)) { + err = cti_channel_gate_op(dev, CTI_GATE_CHAN_ENABLE_ALL, 0); + } else { + if (kstrtoint(buf, 0, &channel)) + return -EINVAL; + + err = cti_channel_gate_op(dev, CTI_GATE_CHAN_ENABLE, channel); + } + return err ? err : size; +} +static DEVICE_ATTR_WO(gate_enable); + +static ssize_t gate_disable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int err = 0, channel = 0; + + if ((size >= 3) && (strncmp(buf, "all", 3) == 0)) { + err = cti_channel_gate_op(dev, CTI_GATE_CHAN_DISABLE_ALL, 0); + } else { + if (kstrtoint(buf, 0, &channel)) + return -EINVAL; + + err = cti_channel_gate_op(dev, CTI_GATE_CHAN_DISABLE, channel); + } + return err ? err : size; +} +static DEVICE_ATTR_WO(gate_disable); + +static int +chan_op_parse(struct device *dev, enum cti_chan_set_op op, const char *buf) +{ + int err = 0, channel = 0; + + if (kstrtoint(buf, 0, &channel)) + return -EINVAL; + + err = cti_channel_setop(dev, op, channel); + return err; + +} + +static ssize_t chan_set_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int err = chan_op_parse(dev, CTI_CHAN_SET, buf); + + return err ? err : size; +} +static DEVICE_ATTR_WO(chan_set); + +static ssize_t chan_clear_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int err = chan_op_parse(dev, CTI_CHAN_CLR, buf); + + return err ? err : size; +} +static DEVICE_ATTR_WO(chan_clear); + +static ssize_t chan_pulse_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int err = chan_op_parse(dev, CTI_CHAN_PULSE, buf); + + return err ? err : size; +} +static DEVICE_ATTR_WO(chan_pulse); + +static ssize_t trig_filter_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + unsigned long val; + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + + spin_lock(&drvdata->spinlock); + val = drvdata->config.trig_filter_enable; + spin_unlock(&drvdata->spinlock); + return scnprintf(buf, PAGE_SIZE, "%s\n", val ? "enabled" : "disabled"); +} + +static ssize_t trig_filter_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + unsigned long val; + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + spin_lock(&drvdata->spinlock); + drvdata->config.trig_filter_enable = !!val; + spin_unlock(&drvdata->spinlock); + return size; +} +static DEVICE_ATTR_RW(trig_filter_enable); + +/* clear all xtrigger / channel programming */ +static ssize_t reset_xtrigs_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int i; + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cti_config *config = &drvdata->config; + + spin_lock(&drvdata->spinlock); + + /* clear the CTI trigger / channel programming registers */ + for (i = 0; i < config->nr_trig_max; i++) { + config->ctiinen[i] = 0; + config->ctiouten[i] = 0; + } + + /* clear the other regs */ + config->ctigate = GENMASK(config->nr_ctm_channels - 1, 0); + config->asicctl = 0; + config->ctiappset = 0; + config->ctiinout_sel = 0; + config->xtrig_rchan_sel = 0; + + /* if enabled then write through */ + if (CTI_PWR_ENA(config)) + cti_write_all_hw_regs(drvdata); + + spin_unlock(&drvdata->spinlock); + return size; +} +static DEVICE_ATTR_WO(reset_xtrigs); + +static ssize_t show_chan_sel_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + u32 val; + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + + val = (u32)drvdata->config.xtrig_rchan_sel; + return scnprintf(buf, PAGE_SIZE, "%d\n", val); +} + +/* select a channel for the show_chan_xtrig function */ +static ssize_t show_chan_sel_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + unsigned long val; + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + if (val > (drvdata->config.nr_ctm_channels - 1)) + return -EINVAL; + + spin_lock(&drvdata->spinlock); + drvdata->config.xtrig_rchan_sel = val; + spin_unlock(&drvdata->spinlock); + return size; +} +static DEVICE_ATTR_RW(show_chan_sel); + +/* for the selected channel - show the signals attached. */ +static ssize_t show_chan_xtrigs_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cti_config *cfg = &drvdata->config; + int used = 0, reg_idx; + int buf_sz = PAGE_SIZE; + u32 chan_mask = BIT(cfg->xtrig_rchan_sel); + + used += scnprintf(buf, buf_sz, "IN: "); + for (reg_idx = 0; + reg_idx < drvdata->config.nr_trig_max; + reg_idx++) { + if (chan_mask & cfg->ctiinen[reg_idx]) { + used += scnprintf(buf + used, buf_sz - used, "%d ", + reg_idx); + } + } + + used += scnprintf(buf + used, buf_sz - used, "OUT: "); + for (reg_idx = 0; + reg_idx < drvdata->config.nr_trig_max; + reg_idx++) { + if (chan_mask & cfg->ctiouten[reg_idx]) { + used += scnprintf(buf + used, buf_sz - used, "%d ", + reg_idx); + } + } + used += scnprintf(buf + used, buf_sz - used, "\n"); + return used; +} +static DEVICE_ATTR_RO(show_chan_xtrigs); + +static ssize_t print_chan_list(struct device *dev, + char *buf, bool inuse) +{ + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cti_config *config = &drvdata->config; + int size, i; + unsigned long inuse_bits = 0, chan_mask; + + /* scan regs to get bitmap of channels in use. */ + spin_lock(&drvdata->spinlock); + for (i = 0; i < config->nr_trig_max; i++) { + inuse_bits |= config->ctiinen[i]; + inuse_bits |= config->ctiouten[i]; + } + spin_unlock(&drvdata->spinlock); + + /* inverse bits if printing free channels */ + if (!inuse) + inuse_bits = ~inuse_bits; + + /* list of channels, or 'none' */ + chan_mask = GENMASK(config->nr_ctm_channels - 1, 0); + if (inuse_bits & chan_mask) + size = bitmap_print_to_pagebuf(true, buf, &inuse_bits, + config->nr_ctm_channels); + else + size = scnprintf(buf, PAGE_SIZE, "none\n"); + return size; +} + +static ssize_t list_inuse_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return print_chan_list(dev, buf, true); +} +static DEVICE_ATTR_RO(list_inuse); + +static ssize_t list_free_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return print_chan_list(dev, buf, false); +} +static DEVICE_ATTR_RO(list_free); + +static ssize_t list_gate_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cti_config *cfg = &drvdata->config; + unsigned long ctigate_bitmask = cfg->ctigate; + int size = 0; + + if (cfg->ctigate == 0) + size = scnprintf(buf, PAGE_SIZE, "none\n"); + else + size = bitmap_print_to_pagebuf(true, buf, &ctigate_bitmask, + cfg->nr_ctm_channels); + return size; +} +static DEVICE_ATTR_RO(list_gate_enable); + +static struct attribute *coresight_cti_channel_attrs[] = { + &dev_attr_trigin_attach.attr, + &dev_attr_trigin_detach.attr, + &dev_attr_trigout_attach.attr, + &dev_attr_trigout_detach.attr, + &dev_attr_gate_enable.attr, + &dev_attr_gate_disable.attr, + &dev_attr_chan_set.attr, + &dev_attr_chan_clear.attr, + &dev_attr_chan_pulse.attr, + &dev_attr_trig_filter_enable.attr, + &dev_attr_reset_xtrigs.attr, + &dev_attr_show_chan_sel.attr, + &dev_attr_show_chan_xtrigs.attr, + &dev_attr_list_inuse.attr, + &dev_attr_list_free.attr, + &dev_attr_list_gate_enable.attr, + NULL, +}; + /* sysfs groups */ static const struct attribute_group coresight_cti_group = { .attrs = coresight_cti_attrs, @@ -495,9 +844,15 @@ static const struct attribute_group coresight_cti_regs_group = { .name = "regs", };
+static const struct attribute_group coresight_cti_channels_group = { + .attrs = coresight_cti_channel_attrs, + .name = "channels", +}; + const struct attribute_group *coresight_cti_groups[] = { &coresight_cti_group, &coresight_cti_mgmt_group, &coresight_cti_regs_group, + &coresight_cti_channels_group, NULL, }; diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 0368fa7c6179..9b0441d8be61 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -36,7 +36,7 @@ static DEFINE_MUTEX(ect_mutex); DEFINE_CORESIGHT_DEVLIST(cti_sys_devs, "cti_sys");
/* write set of regs to hardware - call with spinlock claimed */ -static void cti_write_all_hw_regs(struct cti_drvdata *drvdata) +void cti_write_all_hw_regs(struct cti_drvdata *drvdata) { struct cti_config *config = &drvdata->config; int i; @@ -295,6 +295,161 @@ int cti_add_default_connection(struct device *dev, struct cti_drvdata *drvdata) return ret; }
+/** cti channel api **/ +/* attach/detach channel from trigger - write through if enabled. */ +int cti_channel_trig_op(struct device *dev, enum cti_chan_op op, + enum cti_trig_dir direction, u32 channel_idx, + u32 trigger_idx) +{ + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cti_config *config = &drvdata->config; + u32 trig_bitmask; + u32 chan_bitmask; + u32 reg_value; + int reg_offset; + + /* ensure indexes in range */ + if ((channel_idx >= config->nr_ctm_channels) || + (trigger_idx >= config->nr_trig_max)) + return -EINVAL; + + trig_bitmask = BIT(trigger_idx); + + /* ensure registered triggers and not out filtered */ + if (direction == CTI_TRIG_IN) { + if (!(trig_bitmask & config->trig_in_use)) + return -EINVAL; + } else { + if (!(trig_bitmask & config->trig_out_use)) + return -EINVAL; + + if ((config->trig_filter_enable) && + (config->trig_out_filter & trig_bitmask)) + return -EINVAL; + } + + /* update the local register values */ + chan_bitmask = BIT(channel_idx); + reg_offset = (direction == CTI_TRIG_IN ? CTIINEN(trigger_idx) : + CTIOUTEN(trigger_idx)); + + spin_lock(&drvdata->spinlock); + + /* read - modify write - the trigger / channel enable value */ + reg_value = direction == CTI_TRIG_IN ? config->ctiinen[trigger_idx] : + config->ctiouten[trigger_idx]; + if (op == CTI_CHAN_ATTACH) + reg_value |= chan_bitmask; + else + reg_value &= ~chan_bitmask; + + /* write local copy */ + if (direction == CTI_TRIG_IN) + config->ctiinen[trigger_idx] = reg_value; + else + config->ctiouten[trigger_idx] = reg_value; + + /* write through if enabled */ + if (CTI_PWR_ENA(config)) + cti_write_single_reg(drvdata, reg_offset, reg_value); + spin_unlock(&drvdata->spinlock); + return 0; +} + +int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op, + u32 channel_idx) +{ + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cti_config *config = &drvdata->config; + u32 chan_bitmask; + u32 reg_value; + int err = 0; + + if (channel_idx >= config->nr_ctm_channels) + return -EINVAL; + + chan_bitmask = BIT(channel_idx); + + spin_lock(&drvdata->spinlock); + reg_value = config->ctigate; + switch (op) { + case CTI_GATE_CHAN_ENABLE: + reg_value |= chan_bitmask; + break; + + case CTI_GATE_CHAN_DISABLE: + reg_value &= ~chan_bitmask; + break; + + case CTI_GATE_CHAN_ENABLE_ALL: + reg_value = GENMASK(config->nr_ctm_channels - 1, 0); + break; + + case CTI_GATE_CHAN_DISABLE_ALL: + reg_value = 0x0; + break; + + default: + err = -EINVAL; + break; + } + if (err == 0) { + config->ctigate = reg_value; + if (CTI_PWR_ENA(config)) + cti_write_single_reg(drvdata, CTIGATE, reg_value); + } + spin_unlock(&drvdata->spinlock); + return err; +} + +int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, + u32 channel_idx) +{ + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cti_config *config = &drvdata->config; + u32 chan_bitmask; + u32 reg_value; + u32 reg_offset; + int err = 0; + + if (channel_idx >= config->nr_ctm_channels) + return -EINVAL; + + chan_bitmask = BIT(channel_idx); + + spin_lock(&drvdata->spinlock); + reg_value = config->ctiappset; + switch (op) { + case CTI_CHAN_SET: + config->ctiappset |= chan_bitmask; + reg_value = config->ctiappset; + reg_offset = CTIAPPSET; + break; + + case CTI_CHAN_CLR: + config->ctiappset &= ~chan_bitmask; + reg_value = chan_bitmask; + reg_offset = CTIAPPCLEAR; + break; + + case CTI_CHAN_PULSE: + config->ctiappset &= ~chan_bitmask; + reg_value = chan_bitmask; + reg_offset = CTIAPPPULSE; + break; + + default: + err = -EINVAL; + break; + } + + if ((err == 0) && CTI_PWR_ENA(config)) + cti_write_single_reg(drvdata, reg_offset, reg_value); + spin_unlock(&drvdata->spinlock); + + return err; +} + /** cti ect operations **/ int cti_enable(struct coresight_device *csdev) { diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index db8667a2691c..865d3d0ffb11 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -174,6 +174,32 @@ struct cti_drvdata { void (*csdev_release)(struct device *dev); };
+/* + * Channel operation types. + */ +enum cti_chan_op { + CTI_CHAN_ATTACH, + CTI_CHAN_DETACH, +}; + +enum cti_trig_dir { + CTI_TRIG_IN, + CTI_TRIG_OUT, +}; + +enum cti_chan_gate_op { + CTI_GATE_CHAN_ENABLE, + CTI_GATE_CHAN_DISABLE, + CTI_GATE_CHAN_ENABLE_ALL, + CTI_GATE_CHAN_DISABLE_ALL, +}; + +enum cti_chan_set_op { + CTI_CHAN_SET, + CTI_CHAN_CLR, + CTI_CHAN_PULSE, +}; + /* private cti driver fns & vars */ extern const struct attribute_group *coresight_cti_groups[]; int cti_add_default_connection(struct device *dev, @@ -186,8 +212,16 @@ struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs, int out_sigs); int cti_enable(struct coresight_device *csdev); int cti_disable(struct coresight_device *csdev); +void cti_write_all_hw_regs(struct cti_drvdata *drvdata); void cti_write_intack(struct device *dev, u32 ackval); void cti_write_single_reg(struct cti_drvdata *drvdata, int offset, u32 value); +int cti_channel_trig_op(struct device *dev, enum cti_chan_op op, + enum cti_trig_dir direction, u32 channel_idx, + u32 trigger_idx); +int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op, + u32 channel_idx); +int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, + u32 channel_idx); struct coresight_platform_data * coresight_cti_get_platform_data(struct device *dev);
Hi Mike,
Looks good overall. I have some comments about how we mix integer and string output for write/read for sysfs handles.
On 19/08/2019 22:13, Mike Leach wrote:
Adds a user API to allow programming of CTI by trigger ID and channel number. This will take the channel and trigger ID supplied by the user and program the appropriate register values.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-cti-sysfs.c | 355 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.c | 157 +++++++- drivers/hwtracing/coresight/coresight-cti.h | 34 ++ 3 files changed, 545 insertions(+), 1 deletion(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 4055e392530d..dbbfd1de58b3 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -480,6 +480,355 @@ static struct attribute *coresight_cti_regs_attrs[] = { NULL, }; +/* CTI channel x-trigger programming */ +static int +cti_trig_op_parse(struct device *dev, enum cti_chan_op op,
enum cti_trig_dir dir, const char *buf, size_t size)
+{
- u32 chan_idx;
- u32 trig_idx;
- int items, err = size;
nit: If we set this to -EINVAL, you could remove the else case below. We can overwrite the err with size only when we have parsed properly.
- /* extract chan idx and trigger idx */
- items = sscanf(buf, "%d %d", &chan_idx, &trig_idx);
- if (items) {
To make sure we have got two values parsed, the above check must be :
if (items == 2) {
err = cti_channel_trig_op(dev, op, dir, chan_idx, trig_idx);
if (!err)
err = size;
- } else
err = -EINVAL;
- return err;
+}
+static ssize_t gate_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- int err = 0, channel = 0;
- if ((size >= 3) && (strncmp(buf, "all", 3) == 0)) {
Could we make it strict by making this (size == 4) ? But more on that below.
err = cti_channel_gate_op(dev, CTI_GATE_CHAN_ENABLE_ALL, 0);
- } else {
if (kstrtoint(buf, 0, &channel))
return -EINVAL;
err = cti_channel_gate_op(dev, CTI_GATE_CHAN_ENABLE, channel);
- }
In general I am a bit concerned over mixing string and integer as input for an ABI. I don't have a perfect solution for "all" option, other than using -1 ! What do others think ?
- return err ? err : size;
+} +static DEVICE_ATTR_WO(gate_enable);
+static ssize_t gate_disable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- int err = 0, channel = 0;
- if ((size >= 3) && (strncmp(buf, "all", 3) == 0)) {
err = cti_channel_gate_op(dev, CTI_GATE_CHAN_DISABLE_ALL, 0);
- } else {
if (kstrtoint(buf, 0, &channel))
return -EINVAL;
err = cti_channel_gate_op(dev, CTI_GATE_CHAN_DISABLE, channel);
- }
- return err ? err : size;
+} +static DEVICE_ATTR_WO(gate_disable);
+static ssize_t trig_filter_enable_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- unsigned long val;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- spin_lock(&drvdata->spinlock);
- val = drvdata->config.trig_filter_enable;
- spin_unlock(&drvdata->spinlock);
- return scnprintf(buf, PAGE_SIZE, "%s\n", val ? "enabled" : "disabled");
nit: I am not sure if "enabled"/"disabled" is preferred over 1/0. We follow the latter for enable_sink/source etc. Also for the "store" below for this field. So it may be a good idea to keep this consistent with the rest. e.g this might be more helpful for scripting.
+/* for the selected channel - show the signals attached. */ +static ssize_t show_chan_xtrigs_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *cfg = &drvdata->config;
- int used = 0, reg_idx;
- int buf_sz = PAGE_SIZE;
- u32 chan_mask = BIT(cfg->xtrig_rchan_sel);
- used += scnprintf(buf, buf_sz, "IN: ");
- for (reg_idx = 0;
reg_idx < drvdata->config.nr_trig_max;
To be on the safer side shouldn't we check we have enough space left in the buffer ?
i.e reg_idx < drvdata->config.nr_trig_mmax && used < buf_sz ?
and similar check everywhere below ?
reg_idx++) {
if (chan_mask & cfg->ctiinen[reg_idx]) {
used += scnprintf(buf + used, buf_sz - used, "%d ",
reg_idx);
}
- }
- used += scnprintf(buf + used, buf_sz - used, "OUT: ");
- for (reg_idx = 0;
reg_idx < drvdata->config.nr_trig_max;
reg_idx++) {
if (chan_mask & cfg->ctiouten[reg_idx]) {
used += scnprintf(buf + used, buf_sz - used, "%d ",
reg_idx);
}
- }
- used += scnprintf(buf + used, buf_sz - used, "\n");
- return used;
+} +static DEVICE_ATTR_RO(show_chan_xtrigs);
+static ssize_t print_chan_list(struct device *dev,
char *buf, bool inuse)
+{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *config = &drvdata->config;
- int size, i;
- unsigned long inuse_bits = 0, chan_mask;
- /* scan regs to get bitmap of channels in use. */
- spin_lock(&drvdata->spinlock);
- for (i = 0; i < config->nr_trig_max; i++) {
inuse_bits |= config->ctiinen[i];
inuse_bits |= config->ctiouten[i];
- }
- spin_unlock(&drvdata->spinlock);
- /* inverse bits if printing free channels */
- if (!inuse)
inuse_bits = ~inuse_bits;
- /* list of channels, or 'none' */
- chan_mask = GENMASK(config->nr_ctm_channels - 1, 0);
- if (inuse_bits & chan_mask)
size = bitmap_print_to_pagebuf(true, buf, &inuse_bits,
config->nr_ctm_channels);
- else
size = scnprintf(buf, PAGE_SIZE, "none\n");
Could we keep this empty rather than making "none" ? This could make the parsing easier and consistent (for scripts).
- return size;
+}
+static ssize_t list_inuse_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- return print_chan_list(dev, buf, true);
+} +static DEVICE_ATTR_RO(list_inuse);
+static ssize_t list_free_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- return print_chan_list(dev, buf, false);
+} +static DEVICE_ATTR_RO(list_free);
+static ssize_t list_gate_enable_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *cfg = &drvdata->config;
- unsigned long ctigate_bitmask = cfg->ctigate;
- int size = 0;
- if (cfg->ctigate == 0)
size = scnprintf(buf, PAGE_SIZE, "none\n");
same here, could we keep this empty ?
- else
size = bitmap_print_to_pagebuf(true, buf, &ctigate_bitmask,
cfg->nr_ctm_channels);
- return size;
+} +static DEVICE_ATTR_RO(list_gate_enable);
const struct attribute_group *coresight_cti_groups[] = { &coresight_cti_group, &coresight_cti_mgmt_group, &coresight_cti_regs_group,
- &coresight_cti_channels_group, NULL, };
diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 0368fa7c6179..9b0441d8be61 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -36,7 +36,7 @@ static DEFINE_MUTEX(ect_mutex); DEFINE_CORESIGHT_DEVLIST(cti_sys_devs, "cti_sys"); /* write set of regs to hardware - call with spinlock claimed */ -static void cti_write_all_hw_regs(struct cti_drvdata *drvdata) +void cti_write_all_hw_regs(struct cti_drvdata *drvdata)
What triggers this change in this patch ? Seems like an unrelated change w.r.t the patch.
{ struct cti_config *config = &drvdata->config; int i; @@ -295,6 +295,161 @@ int cti_add_default_connection(struct device *dev, struct cti_drvdata *drvdata) return ret; } +/** cti channel api **/ +/* attach/detach channel from trigger - write through if enabled. */ +int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
enum cti_trig_dir direction, u32 channel_idx,
u32 trigger_idx)
+{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *config = &drvdata->config;
- u32 trig_bitmask;
- u32 chan_bitmask;
- u32 reg_value;
- int reg_offset;
- /* ensure indexes in range */
- if ((channel_idx >= config->nr_ctm_channels) ||
(trigger_idx >= config->nr_trig_max))
return -EINVAL;
- trig_bitmask = BIT(trigger_idx);
- /* ensure registered triggers and not out filtered */
- if (direction == CTI_TRIG_IN) {
if (!(trig_bitmask & config->trig_in_use))
return -EINVAL;
- } else {
if (!(trig_bitmask & config->trig_out_use))
return -EINVAL;
if ((config->trig_filter_enable) &&
(config->trig_out_filter & trig_bitmask))
return -EINVAL;
- }
- /* update the local register values */
- chan_bitmask = BIT(channel_idx);
- reg_offset = (direction == CTI_TRIG_IN ? CTIINEN(trigger_idx) :
CTIOUTEN(trigger_idx));
- spin_lock(&drvdata->spinlock);
- /* read - modify write - the trigger / channel enable value */
- reg_value = direction == CTI_TRIG_IN ? config->ctiinen[trigger_idx] :
config->ctiouten[trigger_idx];
- if (op == CTI_CHAN_ATTACH)
reg_value |= chan_bitmask;
- else
reg_value &= ~chan_bitmask;
- /* write local copy */
- if (direction == CTI_TRIG_IN)
config->ctiinen[trigger_idx] = reg_value;
- else
config->ctiouten[trigger_idx] = reg_value;
- /* write through if enabled */
- if (CTI_PWR_ENA(config))
cti_write_single_reg(drvdata, reg_offset, reg_value);
- spin_unlock(&drvdata->spinlock);
- return 0;
+}
+int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op,
u32 channel_idx)
+{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *config = &drvdata->config;
- u32 chan_bitmask;
- u32 reg_value;
- int err = 0;
- if (channel_idx >= config->nr_ctm_channels)
return -EINVAL;
- chan_bitmask = BIT(channel_idx);
- spin_lock(&drvdata->spinlock);
- reg_value = config->ctigate;
- switch (op) {
- case CTI_GATE_CHAN_ENABLE:
reg_value |= chan_bitmask;
break;
- case CTI_GATE_CHAN_DISABLE:
reg_value &= ~chan_bitmask;
break;
- case CTI_GATE_CHAN_ENABLE_ALL:
reg_value = GENMASK(config->nr_ctm_channels - 1, 0);
break;
- case CTI_GATE_CHAN_DISABLE_ALL:
reg_value = 0x0;
break;
- default:
err = -EINVAL;
break;
- }
- if (err == 0) {
config->ctigate = reg_value;
if (CTI_PWR_ENA(config))
cti_write_single_reg(drvdata, CTIGATE, reg_value);
- }
- spin_unlock(&drvdata->spinlock);
- return err;
+}
+int cti_channel_setop(struct device *dev, enum cti_chan_set_op op,
u32 channel_idx)
+{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *config = &drvdata->config;
- u32 chan_bitmask;
- u32 reg_value;
- u32 reg_offset;
- int err = 0;
- if (channel_idx >= config->nr_ctm_channels)
return -EINVAL;
- chan_bitmask = BIT(channel_idx);
- spin_lock(&drvdata->spinlock);
- reg_value = config->ctiappset;
- switch (op) {
- case CTI_CHAN_SET:
config->ctiappset |= chan_bitmask;
reg_value = config->ctiappset;
reg_offset = CTIAPPSET;
break;
- case CTI_CHAN_CLR:
config->ctiappset &= ~chan_bitmask;
reg_value = chan_bitmask;
reg_offset = CTIAPPCLEAR;
break;
- case CTI_CHAN_PULSE:
config->ctiappset &= ~chan_bitmask;
reg_value = chan_bitmask;
reg_offset = CTIAPPPULSE;
break;
- default:
err = -EINVAL;
break;
- }
- if ((err == 0) && CTI_PWR_ENA(config))
cti_write_single_reg(drvdata, reg_offset, reg_value);
- spin_unlock(&drvdata->spinlock);
- return err;
+}
- /** cti ect operations **/ int cti_enable(struct coresight_device *csdev) {
diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index db8667a2691c..865d3d0ffb11 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -174,6 +174,32 @@ struct cti_drvdata { void (*csdev_release)(struct device *dev); }; +/*
- Channel operation types.
- */
+enum cti_chan_op {
- CTI_CHAN_ATTACH,
- CTI_CHAN_DETACH,
+};
+enum cti_trig_dir {
- CTI_TRIG_IN,
- CTI_TRIG_OUT,
+};
+enum cti_chan_gate_op {
- CTI_GATE_CHAN_ENABLE,
- CTI_GATE_CHAN_DISABLE,
- CTI_GATE_CHAN_ENABLE_ALL,
- CTI_GATE_CHAN_DISABLE_ALL,
+};
+enum cti_chan_set_op {
- CTI_CHAN_SET,
- CTI_CHAN_CLR,
- CTI_CHAN_PULSE,
+};
- /* private cti driver fns & vars */ extern const struct attribute_group *coresight_cti_groups[]; int cti_add_default_connection(struct device *dev,
@@ -186,8 +212,16 @@ struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs, int out_sigs); int cti_enable(struct coresight_device *csdev); int cti_disable(struct coresight_device *csdev); +void cti_write_all_hw_regs(struct cti_drvdata *drvdata); void cti_write_intack(struct device *dev, u32 ackval); void cti_write_single_reg(struct cti_drvdata *drvdata, int offset, u32 value); +int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
enum cti_trig_dir direction, u32 channel_idx,
u32 trigger_idx);
+int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op,
u32 channel_idx);
+int cti_channel_setop(struct device *dev, enum cti_chan_set_op op,
struct coresight_platform_data * coresight_cti_get_platform_data(struct device *dev);u32 channel_idx);
Suzuki
On Fri, 27 Sep 2019 at 07:49, Suzuki K Poulose suzuki.poulose@arm.com wrote:
Hi Mike,
Looks good overall. I have some comments about how we mix integer and string output for write/read for sysfs handles.
On 19/08/2019 22:13, Mike Leach wrote:
Adds a user API to allow programming of CTI by trigger ID and channel number. This will take the channel and trigger ID supplied by the user and program the appropriate register values.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-cti-sysfs.c | 355 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.c | 157 +++++++- drivers/hwtracing/coresight/coresight-cti.h | 34 ++ 3 files changed, 545 insertions(+), 1 deletion(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 4055e392530d..dbbfd1de58b3 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -480,6 +480,355 @@ static struct attribute *coresight_cti_regs_attrs[] = { NULL, };
+/* CTI channel x-trigger programming */ +static int +cti_trig_op_parse(struct device *dev, enum cti_chan_op op,
enum cti_trig_dir dir, const char *buf, size_t size)
+{
u32 chan_idx;
u32 trig_idx;
int items, err = size;
nit: If we set this to -EINVAL, you could remove the else case below. We can overwrite the err with size only when we have parsed properly.
/* extract chan idx and trigger idx */
items = sscanf(buf, "%d %d", &chan_idx, &trig_idx);
if (items) {
To make sure we have got two values parsed, the above check must be :
if (items == 2) {
err = cti_channel_trig_op(dev, op, dir, chan_idx, trig_idx);
if (!err)
err = size;
} else
err = -EINVAL;
return err;
+}
+static ssize_t gate_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
int err = 0, channel = 0;
if ((size >= 3) && (strncmp(buf, "all", 3) == 0)) {
Could we make it strict by making this (size == 4) ? But more on that below.
err = cti_channel_gate_op(dev, CTI_GATE_CHAN_ENABLE_ALL, 0);
} else {
if (kstrtoint(buf, 0, &channel))
return -EINVAL;
err = cti_channel_gate_op(dev, CTI_GATE_CHAN_ENABLE, channel);
}
In general I am a bit concerned over mixing string and integer as input for an ABI. I don't have a perfect solution for "all" option, other than using -1 ! What do others think ?
There is only 4 channel so it would not be overly cumbersome to simply iterate over them. That would fix the mix between integer and strings along with removing the CTI_GATE_CHAN_ENABLE_ALL option.
return err ? err : size;
+} +static DEVICE_ATTR_WO(gate_enable);
+static ssize_t gate_disable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
int err = 0, channel = 0;
if ((size >= 3) && (strncmp(buf, "all", 3) == 0)) {
err = cti_channel_gate_op(dev, CTI_GATE_CHAN_DISABLE_ALL, 0);
} else {
if (kstrtoint(buf, 0, &channel))
return -EINVAL;
err = cti_channel_gate_op(dev, CTI_GATE_CHAN_DISABLE, channel);
}
return err ? err : size;
+} +static DEVICE_ATTR_WO(gate_disable);
+static ssize_t trig_filter_enable_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
unsigned long val;
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
spin_lock(&drvdata->spinlock);
val = drvdata->config.trig_filter_enable;
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%s\n", val ? "enabled" : "disabled");
nit: I am not sure if "enabled"/"disabled" is preferred over 1/0. We follow the latter for enable_sink/source etc. Also for the "store" below for this field. So it may be a good idea to keep this consistent with the rest. e.g this might be more helpful for scripting.
I agree with Suzuki.
Hi,
Agreed - all option removed. Removed appset alteration in pulse store.
Thanks
Mike
On Mon, 30 Sep 2019 at 23:12, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Fri, 27 Sep 2019 at 07:49, Suzuki K Poulose suzuki.poulose@arm.com wrote:
Hi Mike,
Looks good overall. I have some comments about how we mix integer and string output for write/read for sysfs handles.
On 19/08/2019 22:13, Mike Leach wrote:
Adds a user API to allow programming of CTI by trigger ID and channel number. This will take the channel and trigger ID supplied by the user and program the appropriate register values.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-cti-sysfs.c | 355 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.c | 157 +++++++- drivers/hwtracing/coresight/coresight-cti.h | 34 ++ 3 files changed, 545 insertions(+), 1 deletion(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 4055e392530d..dbbfd1de58b3 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -480,6 +480,355 @@ static struct attribute *coresight_cti_regs_attrs[] = { NULL, };
+/* CTI channel x-trigger programming */ +static int +cti_trig_op_parse(struct device *dev, enum cti_chan_op op,
enum cti_trig_dir dir, const char *buf, size_t size)
+{
u32 chan_idx;
u32 trig_idx;
int items, err = size;
nit: If we set this to -EINVAL, you could remove the else case below. We can overwrite the err with size only when we have parsed properly.
/* extract chan idx and trigger idx */
items = sscanf(buf, "%d %d", &chan_idx, &trig_idx);
if (items) {
To make sure we have got two values parsed, the above check must be :
if (items == 2) {
err = cti_channel_trig_op(dev, op, dir, chan_idx, trig_idx);
if (!err)
err = size;
} else
err = -EINVAL;
return err;
+}
+static ssize_t gate_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
int err = 0, channel = 0;
if ((size >= 3) && (strncmp(buf, "all", 3) == 0)) {
Could we make it strict by making this (size == 4) ? But more on that below.
err = cti_channel_gate_op(dev, CTI_GATE_CHAN_ENABLE_ALL, 0);
} else {
if (kstrtoint(buf, 0, &channel))
return -EINVAL;
err = cti_channel_gate_op(dev, CTI_GATE_CHAN_ENABLE, channel);
}
In general I am a bit concerned over mixing string and integer as input for an ABI. I don't have a perfect solution for "all" option, other than using -1 ! What do others think ?
There is only 4 channel so it would not be overly cumbersome to simply iterate over them. That would fix the mix between integer and strings along with removing the CTI_GATE_CHAN_ENABLE_ALL option.
return err ? err : size;
+} +static DEVICE_ATTR_WO(gate_enable);
+static ssize_t gate_disable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
int err = 0, channel = 0;
if ((size >= 3) && (strncmp(buf, "all", 3) == 0)) {
err = cti_channel_gate_op(dev, CTI_GATE_CHAN_DISABLE_ALL, 0);
} else {
if (kstrtoint(buf, 0, &channel))
return -EINVAL;
err = cti_channel_gate_op(dev, CTI_GATE_CHAN_DISABLE, channel);
}
return err ? err : size;
+} +static DEVICE_ATTR_WO(gate_disable);
+static ssize_t trig_filter_enable_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
unsigned long val;
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
spin_lock(&drvdata->spinlock);
val = drvdata->config.trig_filter_enable;
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%s\n", val ? "enabled" : "disabled");
nit: I am not sure if "enabled"/"disabled" is preferred over 1/0. We follow the latter for enable_sink/source etc. Also for the "store" below for this field. So it may be a good idea to keep this consistent with the rest. e.g this might be more helpful for scripting.
I agree with Suzuki.
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
On Mon, Aug 19, 2019 at 10:13:50PM +0100, Mike Leach wrote:
Adds a user API to allow programming of CTI by trigger ID and channel number. This will take the channel and trigger ID supplied by the user and program the appropriate register values.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-cti-sysfs.c | 355 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.c | 157 +++++++- drivers/hwtracing/coresight/coresight-cti.h | 34 ++ 3 files changed, 545 insertions(+), 1 deletion(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 4055e392530d..dbbfd1de58b3 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -480,6 +480,355 @@ static struct attribute *coresight_cti_regs_attrs[] = { NULL, }; +/* CTI channel x-trigger programming */ +static int +cti_trig_op_parse(struct device *dev, enum cti_chan_op op,
enum cti_trig_dir dir, const char *buf, size_t size)
+{
- u32 chan_idx;
- u32 trig_idx;
- int items, err = size;
- /* extract chan idx and trigger idx */
- items = sscanf(buf, "%d %d", &chan_idx, &trig_idx);
- if (items) {
err = cti_channel_trig_op(dev, op, dir, chan_idx, trig_idx);
if (!err)
err = size;
- } else
err = -EINVAL;
- return err;
+}
+static ssize_t trigin_attach_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- return cti_trig_op_parse(dev, CTI_CHAN_ATTACH, CTI_TRIG_IN,
buf, size);
+} +static DEVICE_ATTR_WO(trigin_attach);
+static ssize_t trigin_detach_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- return cti_trig_op_parse(dev, CTI_CHAN_DETACH, CTI_TRIG_IN,
buf, size);
+} +static DEVICE_ATTR_WO(trigin_detach);
+static ssize_t trigout_attach_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- return cti_trig_op_parse(dev, CTI_CHAN_ATTACH, CTI_TRIG_OUT,
buf, size);
+} +static DEVICE_ATTR_WO(trigout_attach);
+static ssize_t trigout_detach_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- return cti_trig_op_parse(dev, CTI_CHAN_DETACH, CTI_TRIG_OUT,
buf, size);
+} +static DEVICE_ATTR_WO(trigout_detach);
+static ssize_t gate_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- int err = 0, channel = 0;
- if ((size >= 3) && (strncmp(buf, "all", 3) == 0)) {
err = cti_channel_gate_op(dev, CTI_GATE_CHAN_ENABLE_ALL, 0);
- } else {
if (kstrtoint(buf, 0, &channel))
return -EINVAL;
err = cti_channel_gate_op(dev, CTI_GATE_CHAN_ENABLE, channel);
- }
- return err ? err : size;
+} +static DEVICE_ATTR_WO(gate_enable);
+static ssize_t gate_disable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- int err = 0, channel = 0;
- if ((size >= 3) && (strncmp(buf, "all", 3) == 0)) {
err = cti_channel_gate_op(dev, CTI_GATE_CHAN_DISABLE_ALL, 0);
- } else {
if (kstrtoint(buf, 0, &channel))
return -EINVAL;
err = cti_channel_gate_op(dev, CTI_GATE_CHAN_DISABLE, channel);
- }
- return err ? err : size;
+} +static DEVICE_ATTR_WO(gate_disable);
+static int +chan_op_parse(struct device *dev, enum cti_chan_set_op op, const char *buf) +{
- int err = 0, channel = 0;
- if (kstrtoint(buf, 0, &channel))
return -EINVAL;
- err = cti_channel_setop(dev, op, channel);
- return err;
+}
+static ssize_t chan_set_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- int err = chan_op_parse(dev, CTI_CHAN_SET, buf);
- return err ? err : size;
+} +static DEVICE_ATTR_WO(chan_set);
+static ssize_t chan_clear_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- int err = chan_op_parse(dev, CTI_CHAN_CLR, buf);
- return err ? err : size;
+} +static DEVICE_ATTR_WO(chan_clear);
+static ssize_t chan_pulse_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- int err = chan_op_parse(dev, CTI_CHAN_PULSE, buf);
- return err ? err : size;
+} +static DEVICE_ATTR_WO(chan_pulse);
+static ssize_t trig_filter_enable_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- unsigned long val;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- spin_lock(&drvdata->spinlock);
- val = drvdata->config.trig_filter_enable;
- spin_unlock(&drvdata->spinlock);
- return scnprintf(buf, PAGE_SIZE, "%s\n", val ? "enabled" : "disabled");
+}
+static ssize_t trig_filter_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- unsigned long val;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- if (kstrtoul(buf, 0, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
- drvdata->config.trig_filter_enable = !!val;
- spin_unlock(&drvdata->spinlock);
- return size;
+} +static DEVICE_ATTR_RW(trig_filter_enable);
+/* clear all xtrigger / channel programming */ +static ssize_t reset_xtrigs_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- int i;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
- /* clear the CTI trigger / channel programming registers */
- for (i = 0; i < config->nr_trig_max; i++) {
config->ctiinen[i] = 0;
config->ctiouten[i] = 0;
- }
- /* clear the other regs */
- config->ctigate = GENMASK(config->nr_ctm_channels - 1, 0);
- config->asicctl = 0;
- config->ctiappset = 0;
- config->ctiinout_sel = 0;
- config->xtrig_rchan_sel = 0;
- /* if enabled then write through */
- if (CTI_PWR_ENA(config))
cti_write_all_hw_regs(drvdata);
- spin_unlock(&drvdata->spinlock);
- return size;
+} +static DEVICE_ATTR_WO(reset_xtrigs);
+static ssize_t show_chan_sel_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- u32 val;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- val = (u32)drvdata->config.xtrig_rchan_sel;
- return scnprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+/* select a channel for the show_chan_xtrig function */ +static ssize_t show_chan_sel_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- unsigned long val;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- if (kstrtoul(buf, 0, &val))
return -EINVAL;
- if (val > (drvdata->config.nr_ctm_channels - 1))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
- drvdata->config.xtrig_rchan_sel = val;
- spin_unlock(&drvdata->spinlock);
- return size;
+} +static DEVICE_ATTR_RW(show_chan_sel);
+/* for the selected channel - show the signals attached. */ +static ssize_t show_chan_xtrigs_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *cfg = &drvdata->config;
- int used = 0, reg_idx;
- int buf_sz = PAGE_SIZE;
- u32 chan_mask = BIT(cfg->xtrig_rchan_sel);
- used += scnprintf(buf, buf_sz, "IN: ");
- for (reg_idx = 0;
reg_idx < drvdata->config.nr_trig_max;
reg_idx++) {
if (chan_mask & cfg->ctiinen[reg_idx]) {
used += scnprintf(buf + used, buf_sz - used, "%d ",
reg_idx);
}
- }
- used += scnprintf(buf + used, buf_sz - used, "OUT: ");
- for (reg_idx = 0;
reg_idx < drvdata->config.nr_trig_max;
reg_idx++) {
if (chan_mask & cfg->ctiouten[reg_idx]) {
used += scnprintf(buf + used, buf_sz - used, "%d ",
reg_idx);
}
- }
- used += scnprintf(buf + used, buf_sz - used, "\n");
- return used;
+} +static DEVICE_ATTR_RO(show_chan_xtrigs);
+static ssize_t print_chan_list(struct device *dev,
char *buf, bool inuse)
+{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *config = &drvdata->config;
- int size, i;
- unsigned long inuse_bits = 0, chan_mask;
- /* scan regs to get bitmap of channels in use. */
- spin_lock(&drvdata->spinlock);
- for (i = 0; i < config->nr_trig_max; i++) {
inuse_bits |= config->ctiinen[i];
inuse_bits |= config->ctiouten[i];
- }
- spin_unlock(&drvdata->spinlock);
- /* inverse bits if printing free channels */
- if (!inuse)
inuse_bits = ~inuse_bits;
- /* list of channels, or 'none' */
- chan_mask = GENMASK(config->nr_ctm_channels - 1, 0);
- if (inuse_bits & chan_mask)
size = bitmap_print_to_pagebuf(true, buf, &inuse_bits,
config->nr_ctm_channels);
- else
size = scnprintf(buf, PAGE_SIZE, "none\n");
- return size;
+}
+static ssize_t list_inuse_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- return print_chan_list(dev, buf, true);
+} +static DEVICE_ATTR_RO(list_inuse);
+static ssize_t list_free_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- return print_chan_list(dev, buf, false);
+} +static DEVICE_ATTR_RO(list_free);
+static ssize_t list_gate_enable_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *cfg = &drvdata->config;
- unsigned long ctigate_bitmask = cfg->ctigate;
- int size = 0;
- if (cfg->ctigate == 0)
size = scnprintf(buf, PAGE_SIZE, "none\n");
- else
size = bitmap_print_to_pagebuf(true, buf, &ctigate_bitmask,
cfg->nr_ctm_channels);
- return size;
+} +static DEVICE_ATTR_RO(list_gate_enable);
+static struct attribute *coresight_cti_channel_attrs[] = {
- &dev_attr_trigin_attach.attr,
- &dev_attr_trigin_detach.attr,
- &dev_attr_trigout_attach.attr,
- &dev_attr_trigout_detach.attr,
- &dev_attr_gate_enable.attr,
- &dev_attr_gate_disable.attr,
- &dev_attr_chan_set.attr,
- &dev_attr_chan_clear.attr,
- &dev_attr_chan_pulse.attr,
- &dev_attr_trig_filter_enable.attr,
- &dev_attr_reset_xtrigs.attr,
- &dev_attr_show_chan_sel.attr,
- &dev_attr_show_chan_xtrigs.attr,
- &dev_attr_list_inuse.attr,
- &dev_attr_list_free.attr,
- &dev_attr_list_gate_enable.attr,
- NULL,
+};
/* sysfs groups */ static const struct attribute_group coresight_cti_group = { .attrs = coresight_cti_attrs, @@ -495,9 +844,15 @@ static const struct attribute_group coresight_cti_regs_group = { .name = "regs", }; +static const struct attribute_group coresight_cti_channels_group = {
- .attrs = coresight_cti_channel_attrs,
- .name = "channels",
+};
const struct attribute_group *coresight_cti_groups[] = { &coresight_cti_group, &coresight_cti_mgmt_group, &coresight_cti_regs_group,
- &coresight_cti_channels_group, NULL,
}; diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 0368fa7c6179..9b0441d8be61 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -36,7 +36,7 @@ static DEFINE_MUTEX(ect_mutex); DEFINE_CORESIGHT_DEVLIST(cti_sys_devs, "cti_sys"); /* write set of regs to hardware - call with spinlock claimed */ -static void cti_write_all_hw_regs(struct cti_drvdata *drvdata) +void cti_write_all_hw_regs(struct cti_drvdata *drvdata) { struct cti_config *config = &drvdata->config; int i; @@ -295,6 +295,161 @@ int cti_add_default_connection(struct device *dev, struct cti_drvdata *drvdata) return ret; } +/** cti channel api **/ +/* attach/detach channel from trigger - write through if enabled. */ +int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
enum cti_trig_dir direction, u32 channel_idx,
u32 trigger_idx)
+{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *config = &drvdata->config;
- u32 trig_bitmask;
- u32 chan_bitmask;
- u32 reg_value;
- int reg_offset;
- /* ensure indexes in range */
- if ((channel_idx >= config->nr_ctm_channels) ||
(trigger_idx >= config->nr_trig_max))
return -EINVAL;
- trig_bitmask = BIT(trigger_idx);
- /* ensure registered triggers and not out filtered */
- if (direction == CTI_TRIG_IN) {
if (!(trig_bitmask & config->trig_in_use))
return -EINVAL;
- } else {
if (!(trig_bitmask & config->trig_out_use))
return -EINVAL;
if ((config->trig_filter_enable) &&
(config->trig_out_filter & trig_bitmask))
return -EINVAL;
- }
- /* update the local register values */
- chan_bitmask = BIT(channel_idx);
- reg_offset = (direction == CTI_TRIG_IN ? CTIINEN(trigger_idx) :
CTIOUTEN(trigger_idx));
- spin_lock(&drvdata->spinlock);
- /* read - modify write - the trigger / channel enable value */
- reg_value = direction == CTI_TRIG_IN ? config->ctiinen[trigger_idx] :
config->ctiouten[trigger_idx];
- if (op == CTI_CHAN_ATTACH)
reg_value |= chan_bitmask;
- else
reg_value &= ~chan_bitmask;
- /* write local copy */
- if (direction == CTI_TRIG_IN)
config->ctiinen[trigger_idx] = reg_value;
- else
config->ctiouten[trigger_idx] = reg_value;
- /* write through if enabled */
- if (CTI_PWR_ENA(config))
cti_write_single_reg(drvdata, reg_offset, reg_value);
- spin_unlock(&drvdata->spinlock);
- return 0;
+}
+int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op,
u32 channel_idx)
+{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *config = &drvdata->config;
- u32 chan_bitmask;
- u32 reg_value;
- int err = 0;
- if (channel_idx >= config->nr_ctm_channels)
return -EINVAL;
- chan_bitmask = BIT(channel_idx);
- spin_lock(&drvdata->spinlock);
- reg_value = config->ctigate;
- switch (op) {
- case CTI_GATE_CHAN_ENABLE:
reg_value |= chan_bitmask;
break;
- case CTI_GATE_CHAN_DISABLE:
reg_value &= ~chan_bitmask;
break;
- case CTI_GATE_CHAN_ENABLE_ALL:
reg_value = GENMASK(config->nr_ctm_channels - 1, 0);
break;
- case CTI_GATE_CHAN_DISABLE_ALL:
reg_value = 0x0;
break;
- default:
err = -EINVAL;
break;
- }
- if (err == 0) {
config->ctigate = reg_value;
if (CTI_PWR_ENA(config))
cti_write_single_reg(drvdata, CTIGATE, reg_value);
- }
- spin_unlock(&drvdata->spinlock);
- return err;
+}
+int cti_channel_setop(struct device *dev, enum cti_chan_set_op op,
u32 channel_idx)
+{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *config = &drvdata->config;
- u32 chan_bitmask;
- u32 reg_value;
- u32 reg_offset;
- int err = 0;
- if (channel_idx >= config->nr_ctm_channels)
return -EINVAL;
- chan_bitmask = BIT(channel_idx);
- spin_lock(&drvdata->spinlock);
- reg_value = config->ctiappset;
- switch (op) {
- case CTI_CHAN_SET:
config->ctiappset |= chan_bitmask;
reg_value = config->ctiappset;
reg_offset = CTIAPPSET;
break;
- case CTI_CHAN_CLR:
config->ctiappset &= ~chan_bitmask;
reg_value = chan_bitmask;
reg_offset = CTIAPPCLEAR;
break;
- case CTI_CHAN_PULSE:
config->ctiappset &= ~chan_bitmask;
I understand managing config->ctiappset for CTI_CHAN_SET and CTI_CHAN_CLR operations but not for CTI_CHAN_PULSE. From what I read in the documentation setting a bit in CTIAPPPULSE will create a pulse for that channel regardless of the value of register CTIAPPSET.
reg_value = chan_bitmask;
reg_offset = CTIAPPPULSE;
break;
- default:
err = -EINVAL;
break;
- }
- if ((err == 0) && CTI_PWR_ENA(config))
cti_write_single_reg(drvdata, reg_offset, reg_value);
- spin_unlock(&drvdata->spinlock);
- return err;
+}
/** cti ect operations **/ int cti_enable(struct coresight_device *csdev) { diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index db8667a2691c..865d3d0ffb11 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -174,6 +174,32 @@ struct cti_drvdata { void (*csdev_release)(struct device *dev); }; +/*
- Channel operation types.
- */
+enum cti_chan_op {
- CTI_CHAN_ATTACH,
- CTI_CHAN_DETACH,
+};
+enum cti_trig_dir {
- CTI_TRIG_IN,
- CTI_TRIG_OUT,
+};
+enum cti_chan_gate_op {
- CTI_GATE_CHAN_ENABLE,
- CTI_GATE_CHAN_DISABLE,
- CTI_GATE_CHAN_ENABLE_ALL,
- CTI_GATE_CHAN_DISABLE_ALL,
+};
+enum cti_chan_set_op {
- CTI_CHAN_SET,
- CTI_CHAN_CLR,
- CTI_CHAN_PULSE,
+};
/* private cti driver fns & vars */ extern const struct attribute_group *coresight_cti_groups[]; int cti_add_default_connection(struct device *dev, @@ -186,8 +212,16 @@ struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs, int out_sigs); int cti_enable(struct coresight_device *csdev); int cti_disable(struct coresight_device *csdev); +void cti_write_all_hw_regs(struct cti_drvdata *drvdata); void cti_write_intack(struct device *dev, u32 ackval); void cti_write_single_reg(struct cti_drvdata *drvdata, int offset, u32 value); +int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
enum cti_trig_dir direction, u32 channel_idx,
u32 trigger_idx);
+int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op,
u32 channel_idx);
+int cti_channel_setop(struct device *dev, enum cti_chan_set_op op,
u32 channel_idx);
struct coresight_platform_data * coresight_cti_get_platform_data(struct device *dev); -- 2.17.1
Adds new .txt file describing the bindings required to define CTI in the device trees.
Adds an include file to dt-bindings/arm to define constants describing common signal functionality used in CoreSight and generic usage.
Signed-off-by: Mike Leach mike.leach@linaro.org --- .../bindings/arm/coresight-ect-cti.txt | 396 ++++++++++++++++++ .../devicetree/bindings/arm/coresight.txt | 7 + MAINTAINERS | 2 + include/dt-bindings/arm/coresight-cti-dt.h | 36 ++ 4 files changed, 441 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/coresight-ect-cti.txt create mode 100644 include/dt-bindings/arm/coresight-cti-dt.h
diff --git a/Documentation/devicetree/bindings/arm/coresight-ect-cti.txt b/Documentation/devicetree/bindings/arm/coresight-ect-cti.txt new file mode 100644 index 000000000000..5f78b610be4d --- /dev/null +++ b/Documentation/devicetree/bindings/arm/coresight-ect-cti.txt @@ -0,0 +1,396 @@ +*CoreSight Embedded Cross Trigger Components + +The CoreSight Embedded Cross Trigger (ECT) consists of CTI devices connected +to one or more CoreSight components and/or a CPU, with CTIs interconnected in +a star topology via the CTM (which is not programmable). The ECT components +are not part of the trace generation data path and are thus not part of the +CoreSight graph described in the general CoreSight bindings file coresight.txt. + +The CTI component properties define the connections between the individual CTI +and the components it is directly connected to, consisting of input and output +hardware trigger signals. CTIs can have a maximum number of input and output +hardware trigger signals (8 each for v1 CTI, 32 each for v2 CTI). The number is +defined at design time, the maximum of each defined in the DEVID register. +Note that some hardware trigger signals can be connected to non-CoreSight +components (e.g. UART etc) depending on hardware implementation. + +CTIs are interconnected in a star topology via the CTM, using a number of +programmable channels usually 4, but again implementation defined and described +in the DEVID register. The star topology is not required to be described in the +bindings as the actual connections are software programmable. + +In general the connections between CTI and components via the trigger signals +are implementation defined, other than when v8 core and ETM is present. The v8 +architecture defines the required signal connections between CPU core and CTI, +and ETM and CTI, if the ETM if present. + +Certain triggers between CoreSight devices and the CTI have specific types / +usages. These can be defined along with the signal indexes with the constants +defined in <dt-bindings/arm/coresight-cti-dt.h> + +For example a CTI connected to a core will usually have a DBGREQ signal. This +is defined in the binding as type PE_EDBGREQ. These types will appear in an +optional array alongside the signal indexes. Omitting types will default all +signals to GEN_IO. + +The minimum required binding for a CTI consists of only the following required +properties defined in coresight.txt:- + +* Required properties: + * compatible: These have to be supplemented with "arm,primecell" as + drivers are using the AMBA bus interface. + - Coresight Cross Trigger Interface (CTI): + "arm,coresight-cti", "arm,primecell"; + * reg + * clocks + * clock-names + +e.g.(1) +/* sys cti 0 */ +cti0: cti@20020000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x20020000 0x1000>; + + clocks = <&soc_smc50mhz>; + clock-names = "apb_pclk"; + power-domains = <&scpi_devpd 0>; +}; + +This will result in the driver using the DEVID register to set the +input and output triggers and channels in use. Any user / client +application will require additional information on the connections +between the CTI and other components for correct operation. + +Where information is immediately available for the component connections then +a series of trigger connection nodes can be defined (trig-conns). + +These connections explicitly define the input and output triggers between the +CTI and a connected component. Connections to an cpu use the standard "cpu" +property, connections to other CoreSight components use the arm,cs-dev-assoc +property. + +e.g.(2) +/* CPU CTI connected to Core and ETM */ +cti@858000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x858000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>; + clock-names = "apb_pclk"; + + trig-conns@0 { + arm,trig-in-sigs = <4 5 6 7>; + arm,trig-in-types = <ETM_EXTOUT + ETM_EXTOUT + ETM_EXTOUT + ETM_EXTOUT>; + arm,trig-out-sigs = <4 5 6 7>; + arm,trig-out-types = <ETM_EXTIN + ETM_EXTIN + ETM_EXTIN + ETM_EXTIN>; + arm,cs-dev-assoc = <&etm0>; + }; + + trig-conns@1 { + cpu = <&CPU0>; + arm,trig-in-sigs = <0 1>; + arm,trig-in-types = <PE_DBGTRIGGER + PE_PMUIRQ>; + arm,trig-out-sigs=<0 1 2 >; + arm,trig-out-types = <PE_EDBGREQ + PE_DBGRESTART + PE_CTIIRQ>; + arm,trig-filters = <0>; + }; +}; + +Note that where input and output triggers are defined as above, then the driver +will limit the channel connection sysfs API to using only the defined signals. + +The arm,trig-filters property blocks output signals that could cause system +issues if set - such as the PE_EDBGREQ signal into a CPU. The filtering is +enabled by default, but can be disabled at runtime. + +Where the signals are connected to a device that is not CoreSight device then +no association is registered. In this case a name can be used to identify the +component (arm,trig-conn-name) + +e.g.(3) +/* CTI connected to none coresight devices */ +cti@20110000 { /* Juno sys_cti_1 */ + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0 0x20110000 0 0x1000>; + + clocks = <&soc_smc50mhz>; + clock-names = "apb_pclk"; + power-domains = <&scpi_devpd 0>; + + trig-conns@0 { + arm,trig-in-sigs=<0>; + arm,trig-in-types=<GEN_INTREQ>; + arm,trig-out-sigs=<0>; + arm,trig-out-types=<GEN_HALTREQ>; + arm,trig-conn-name = "sys_profiler"; + }; + + trig-conns@1 { + arm,trig-out-sigs=<2 3>; + arm,trig-out-types=<GEN_HALTREQ GEN_RESTARTREQ>; + arm,trig-conn-name = "watchdog"; + }; + + trig-conns@2 { + arm,trig-out-sigs=<1 6>; + arm,trig-out-types=<GEN_HALTREQ GEN_RESTARTREQ>; + arm,trig-conn-name = "g_counter"; + }; +}; + +Finally, a CTI that is an architecturally defined v8 CTI connected to a cpu +and optional ETM may be declared as: + +e.g.(4) +/* v8 architectural CTI, connected to core and ETM */ +cti@859000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x859000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>; + clock-names = "apb_pclk"; + + arm,cti-v8-arch; + cpu = <&CPU1>; + arm,cs-dev-assoc = <&etm1>; +}; + +This example will result in the same internal structure as e.g.(2) + +The arm,cti-v8-arch property declares this as a v8 CTI, the cpu property must +be present, and a single arm,cs-dev-assoc may be present to define an attached +ETM. No additional trig-conns nodes are permitted. The driver will build a +connection model according to architectural requirements. This will include +a filter on the CPU dbgreq signal as described above. + +All the CTI devices are associated with a CTM. On many systems there will be a +single effective CTM (one CTM, or multiple CTMs all interconnected), but it is +possible that systems can have nets of CTIs+CTM that are not interconnected by +a CTM. On these systems a CTM index is declared to associate CTI devices that +are interconnected via the CTM. + + e.g. + arm,cti-ctm-id=<2> + +CTI devices with the same CTM ID are considered connected by the CTM. If this +parameter is absent then all CTIs are considered interconnected by the same +CTM. + +*Summary of CTI required properties: + + * compatible : should be "arm,coresight-cti"; supplemented with + "arm,primecell" since this driver is using the AMBA bus + interface. + + * reg: physical base address and length of the register + set(s) of the component. + + * clocks: the clocks associated to this component. + + * clock-names: the name of the clocks referenced by the code. + Since we are using the AMBA framework, the name of the clock + providing the interconnect should be "apb_pclk", and some + coresight blocks also have an additional clock "atclk", which + clocks the core of that coresight component. The latter clock + is optional. + +*Summary of CTI optional properties: + + * trig-conns: defines a connection node between CTI and a component. + Component may be a CPU, CoreSight device, any other hardware device + or simple external IO lines. + + * arm,cti-v8-arch: Declares this CTI device as a v8 architecturally + defined device. Use in CTI base node only, no additional trig-conns + nodes permitted if this is declared. + + * cpu: defines a phandle reference to an associated CPU. Used in + trig-conns node, or in CTI base node when arm,cti-v8-arch present. + + * arm,cs-dev-assoc: defines a phandle reference to an associated + CoreSight trace device. When the associated trace device is enabled, + then the respective CTI will be enabled. Use in a trig-conns node, + or in CTI base node when arm,cti-v8-arch present. If the associated + device has not been registered then the node name will be stored as + the connection name for later resolution. If the associated device is + not a CoreSight device or not registered then the node name will + remain the connection name and automatic enabling will not occur. + + * arm,cti-ctm-id: Defines the interconnecting CTM for this device. + Use in CTI base node. + + * Properties valid in the trig-conns node: + + * arm,trig-in-sigs: List of CTI trigger in signals in use by a + trig-conns node. + + * arm,trig-in-types: List of types for the CTI trigger in + signals. Types in this array match to the corresponding signal + in the arm,trig-in-sigs array. If the -types array is smaller, + or omitted completely, then the types will default to GEN_IO. + + * arm,trig-out-sigs: List of CTI trigger out signals in use by a + trig-conns node. + + * arm,trig-out-types: List of types for the CTI trigger out + signals. Types in this array match to the corresponding signal + in the arm,trig-out-sigs array. If the "-types" array is + smaller, or omitted completely, then the types will default + to GEN_IO. + + * arm-trig-filters: List of CTI trigger out signals that will be + blocked from becoming active, unless filtering is disabled on + the driver. + + *arm,trig-conn-name: defines a connection name that will be + displayed, if not overridden by the name of associated device + from arm,cs-dev-assoc or the CPU. Principle use for CTI that + are connected to non-CoreSight devices, or external IO. + +e.g.(5) Combined examples showing all properties: + +a) Minimum CTI definition +cti0: cti@20020000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x20020000 0x1000>; + + clocks = <&soc_smc50mhz>; + clock-names = "apb_pclk"; +}; + +b) v8 architecturally defined CTI - CPU + ETM connections. +cti@859000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x859000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>; + clock-names = "apb_pclk"; + + arm,cti-v8-arch; + cpu = <&CPU1>; + arm,cs-dev-assoc = <&etm1>; +}; + +c) Implementation defined CTI - CPU + ETM connections. +cti@858000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x858000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>; + clock-names = "apb_pclk"; + + trig-conns@0 { + arm,trig-in-sigs = <4 5 6 7>; + arm,trig-in-types = <ETM_EXTOUT + ETM_EXTOUT + ETM_EXTOUT + ETM_EXTOUT>; + arm,trig-out-sigs = <4 5 6 7>; + arm,trig-out-types = <ETM_EXTIN + ETM_EXTIN + ETM_EXTIN + ETM_EXTIN>; + arm,cs-dev-assoc = <&etm0>; + }; + + trig-conns@1 { + cpu = <&CPU0>; + arm,trig-in-sigs = <0 1>; + arm,trig-in-types = <PE_DBGTRIGGER + PE_PMUIRQ>; + arm,trig-out-sigs=<0 1 2 >; + arm,trig-out-types = <PE_EDBGREQ + PE_DBGRESTART + PE_CTIIRQ>; + arm,trig-filters = <0>; + }; + arm,cti-ctm-id = <1>; +}; + +d) Implementation defined CTI - Coresight STM, ETF, ETR connections. +cti@20020000 { /*Juno sys_cti_0 */ + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0 0x20020000 0 0x1000>; + + clocks = <&soc_smc50mhz>; + clock-names = "apb_pclk"; + power-domains = <&scpi_devpd 0>; + + trig-conns@0 { + arm,trig-in-sigs=<2 3>; + arm,trig-in-types=<SNK_FULL + SNK_ACQCOMP>; + arm,trig-out-sigs=<0 1>; + arm,trig-out-types=<SNK_FLUSHIN + SNK_TRIGIN>; + arm,cs-dev-assoc = <&etr_sys>; + }; + + trig-conns@1 { + arm,trig-in-sigs=<0 1>; + arm,trig-in-types=<SNK_FULL + SNK_ACQCOMP>; + arm,trig-out-sigs=<7 6>; + arm,trig-out-types=<SNK_FLUSHIN + SNK_TRIGIN>; + arm,cs-dev-assoc = <&etf_sys0>; + }; + + trig-conns@2 { + arm,trig-in-sigs=<4 5 6 7>; + arm,trig-in-types=<STM_TOUT_SPTE + STM_TOUT_SW + STM_TOUT_HETE + STM_ASYNCOUT>; + arm,trig-out-sigs=<4 5>; + arm,trig-out-types=<STM_HWEVENT + STM_HWEVENT>; + arm,cs-dev-assoc = <&stm_sys>; + }; + + trig-conns@3 { + arm,trig-out-sigs=<2 3>; + arm,trig-out-types=<SNK_FLUSHIN + SNK_TRIGIN>; + arm,cs-dev-assoc = <&tpiu_sys>; + }; +}; + +e) Implementation defined CTI - none CoreSight component connections. +cti@20110000 { /* Juno sys_cti_1 */ + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0 0x20110000 0 0x1000>; + + clocks = <&soc_smc50mhz>; + clock-names = "apb_pclk"; + power-domains = <&scpi_devpd 0>; + + trig-conns@0 { + arm,trig-in-sigs=<0>; + arm,trig-in-types=<GEN_INTREQ>; + arm,trig-out-sigs=<0>; + arm,trig-out-types=<GEN_HALTREQ>; + arm,trig-conn-name = "sys_profiler"; + }; + + trig-conns@1 { + arm,trig-out-sigs=<2 3>; + arm,trig-out-types=<GEN_HALTREQ GEN_RESTARTREQ>; + arm,trig-conn-name = "watchdog"; + }; + + trig-conns@2 { + arm,trig-out-sigs=<1 6>; + arm,trig-out-types=<GEN_HALTREQ GEN_RESTARTREQ>; + arm,trig-conn-name = "g_counter"; + }; +}; diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt index fcc3bacfd8bc..a24713e48304 100644 --- a/Documentation/devicetree/bindings/arm/coresight.txt +++ b/Documentation/devicetree/bindings/arm/coresight.txt @@ -45,6 +45,10 @@ its hardware characteristcs. - Coresight Address Translation Unit (CATU) "arm,coresight-catu", "arm,primecell";
+ - Coresight Cross Trigger Interface (CTI): + "arm,coresight-cti", "arm,primecell"; + See coresight-ect-cti.txt for full CTI definitions. + * reg: physical base address and length of the register set(s) of the component.
@@ -72,6 +76,9 @@ its hardware characteristcs. * reg-names: the only acceptable values are "stm-base" and "stm-stimulus-base", each corresponding to the areas defined in "reg".
+* Required properties for Coresight Cross Trigger Interface (CTI) + See coresight-ect-cti.txt for full CTI definitions. + * Required properties for devices that don't show up on the AMBA bus, such as non-configurable replicators and non-configurable funnels:
diff --git a/MAINTAINERS b/MAINTAINERS index 783569e3c4b4..a81f3bd8340a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1582,10 +1582,12 @@ R: Suzuki K Poulose suzuki.poulose@arm.com L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: drivers/hwtracing/coresight/* +F: include/dt-bindings/arm/coresight-cti-dt.h F: Documentation/trace/coresight.txt F: Documentation/trace/coresight-cpu-debug.txt F: Documentation/devicetree/bindings/arm/coresight.txt F: Documentation/devicetree/bindings/arm/coresight-cpu-debug.txt +F: Documentation/devicetree/bindings/arm/coresight-ect-cti.txt F: Documentation/ABI/testing/sysfs-bus-coresight-devices-* F: tools/perf/arch/arm/util/pmu.c F: tools/perf/arch/arm/util/auxtrace.c diff --git a/include/dt-bindings/arm/coresight-cti-dt.h b/include/dt-bindings/arm/coresight-cti-dt.h new file mode 100644 index 000000000000..88580b5a0388 --- /dev/null +++ b/include/dt-bindings/arm/coresight-cti-dt.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This header provides constants for the defined trigger signal + * types on CoreSight CTI. + */ + +#ifndef _DT_BINDINGS_ARM_CORESIGHT_CTI_DT_H +#define _DT_BINDINGS_ARM_CORESIGHT_CTI_DT_H + +#define GEN_IO 0 +#define GEN_INTREQ 1 +#define GEN_INTACK 2 +#define GEN_HALTREQ 3 +#define GEN_RESTARTREQ 4 +#define PE_EDBGREQ 5 +#define PE_DBGRESTART 6 +#define PE_CTIIRQ 7 +#define PE_PMUIRQ 8 +#define PE_DBGTRIGGER 9 +#define ETM_EXTOUT 10 +#define ETM_EXTIN 11 +#define SNK_FULL 12 +#define SNK_ACQCOMP 13 +#define SNK_FLUSHCOMP 14 +#define SNK_FLUSHIN 15 +#define SNK_TRIGIN 16 +#define STM_ASYNCOUT 17 +#define STM_TOUT_SPTE 18 +#define STM_TOUT_SW 19 +#define STM_TOUT_HETE 20 +#define STM_HWEVENT 21 +#define ELA_TSTART 22 +#define ELA_TSTOP 23 +#define ELA_DBGREQ 24 + +#endif /*_DT_BINDINGS_ARM_CORESIGHT_CTI_DT_H */
On Mon, Aug 19, 2019 at 10:13:51PM +0100, Mike Leach wrote:
Adds new .txt file describing the bindings required to define CTI in the device trees.
Adds an include file to dt-bindings/arm to define constants describing common signal functionality used in CoreSight and generic usage.
As we talked about, this will need to comply with the new DT schema format but I decided to give it a read anyway.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../bindings/arm/coresight-ect-cti.txt | 396 ++++++++++++++++++ .../devicetree/bindings/arm/coresight.txt | 7 + MAINTAINERS | 2 + include/dt-bindings/arm/coresight-cti-dt.h | 36 ++ 4 files changed, 441 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/coresight-ect-cti.txt create mode 100644 include/dt-bindings/arm/coresight-cti-dt.h
diff --git a/Documentation/devicetree/bindings/arm/coresight-ect-cti.txt b/Documentation/devicetree/bindings/arm/coresight-ect-cti.txt new file mode 100644 index 000000000000..5f78b610be4d --- /dev/null +++ b/Documentation/devicetree/bindings/arm/coresight-ect-cti.txt @@ -0,0 +1,396 @@ +*CoreSight Embedded Cross Trigger Components
+The CoreSight Embedded Cross Trigger (ECT) consists of CTI devices connected +to one or more CoreSight components and/or a CPU, with CTIs interconnected in +a star topology via the CTM (which is not programmable). The ECT components +are not part of the trace generation data path and are thus not part of the +CoreSight graph described in the general CoreSight bindings file coresight.txt.
+The CTI component properties define the connections between the individual CTI +and the components it is directly connected to, consisting of input and output +hardware trigger signals. CTIs can have a maximum number of input and output +hardware trigger signals (8 each for v1 CTI, 32 each for v2 CTI). The number is +defined at design time, the maximum of each defined in the DEVID register. +Note that some hardware trigger signals can be connected to non-CoreSight +components (e.g. UART etc) depending on hardware implementation.
+CTIs are interconnected in a star topology via the CTM, using a number of +programmable channels usually 4, but again implementation defined and described +in the DEVID register. The star topology is not required to be described in the +bindings as the actual connections are software programmable.
+In general the connections between CTI and components via the trigger signals +are implementation defined, other than when v8 core and ETM is present. The v8 +architecture defines the required signal connections between CPU core and CTI, +and ETM and CTI, if the ETM if present.
+Certain triggers between CoreSight devices and the CTI have specific types / +usages. These can be defined along with the signal indexes with the constants +defined in <dt-bindings/arm/coresight-cti-dt.h>
+For example a CTI connected to a core will usually have a DBGREQ signal. This +is defined in the binding as type PE_EDBGREQ. These types will appear in an +optional array alongside the signal indexes. Omitting types will default all +signals to GEN_IO.
+The minimum required binding for a CTI consists of only the following required +properties defined in coresight.txt:-
+* Required properties:
- compatible: These have to be supplemented with "arm,primecell" as
drivers are using the AMBA bus interface.
- Coresight Cross Trigger Interface (CTI):
"arm,coresight-cti", "arm,primecell";
I think the above requires better formatting.
- reg
- clocks
- clock-names
+e.g.(1) +/* sys cti 0 */ +cti0: cti@20020000 {
- compatible = "arm,coresight-cti", "arm,primecell";
- reg = <0x20020000 0x1000>;
- clocks = <&soc_smc50mhz>;
- clock-names = "apb_pclk";
- power-domains = <&scpi_devpd 0>;
+};
+This will result in the driver using the DEVID register to set the +input and output triggers and channels in use. Any user / client +application will require additional information on the connections +between the CTI and other components for correct operation.
+Where information is immediately available for the component connections then +a series of trigger connection nodes can be defined (trig-conns).
+These connections explicitly define the input and output triggers between the +CTI and a connected component. Connections to an cpu use the standard "cpu"
s/an cpu/a cpu
+property, connections to other CoreSight components use the arm,cs-dev-assoc +property.
+e.g.(2) +/* CPU CTI connected to Core and ETM */ +cti@858000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x858000 0x1000>;
clocks = <&rpmcc RPM_QDSS_CLK>;
clock-names = "apb_pclk";
trig-conns@0 {
arm,trig-in-sigs = <4 5 6 7>;
arm,trig-in-types = <ETM_EXTOUT
ETM_EXTOUT
ETM_EXTOUT
ETM_EXTOUT>;
arm,trig-out-sigs = <4 5 6 7>;
arm,trig-out-types = <ETM_EXTIN
ETM_EXTIN
ETM_EXTIN
ETM_EXTIN>;
arm,cs-dev-assoc = <&etm0>;
};
trig-conns@1 {
cpu = <&CPU0>;
arm,trig-in-sigs = <0 1>;
arm,trig-in-types = <PE_DBGTRIGGER
PE_PMUIRQ>;
arm,trig-out-sigs=<0 1 2 >;
arm,trig-out-types = <PE_EDBGREQ
PE_DBGRESTART
PE_CTIIRQ>;
arm,trig-filters = <0>;
};
+};
+Note that where input and output triggers are defined as above, then the driver +will limit the channel connection sysfs API to using only the defined signals.
+The arm,trig-filters property blocks output signals that could cause system +issues if set - such as the PE_EDBGREQ signal into a CPU. The filtering is +enabled by default, but can be disabled at runtime.
+Where the signals are connected to a device that is not CoreSight device then +no association is registered. In this case a name can be used to identify the +component (arm,trig-conn-name)
+e.g.(3) +/* CTI connected to none coresight devices */ +cti@20110000 { /* Juno sys_cti_1 */
- compatible = "arm,coresight-cti", "arm,primecell";
- reg = <0 0x20110000 0 0x1000>;
- clocks = <&soc_smc50mhz>;
- clock-names = "apb_pclk";
- power-domains = <&scpi_devpd 0>;
- trig-conns@0 {
arm,trig-in-sigs=<0>;
arm,trig-in-types=<GEN_INTREQ>;
arm,trig-out-sigs=<0>;
arm,trig-out-types=<GEN_HALTREQ>;
arm,trig-conn-name = "sys_profiler";
- };
- trig-conns@1 {
arm,trig-out-sigs=<2 3>;
arm,trig-out-types=<GEN_HALTREQ GEN_RESTARTREQ>;
arm,trig-conn-name = "watchdog";
- };
- trig-conns@2 {
arm,trig-out-sigs=<1 6>;
arm,trig-out-types=<GEN_HALTREQ GEN_RESTARTREQ>;
arm,trig-conn-name = "g_counter";
- };
+};
+Finally, a CTI that is an architecturally defined v8 CTI connected to a cpu
To be consistent with what you have in the previous paragraphs:
s/cpu/CPU
+and optional ETM may be declared as:
+e.g.(4) +/* v8 architectural CTI, connected to core and ETM */ +cti@859000 {
- compatible = "arm,coresight-cti", "arm,primecell";
- reg = <0x859000 0x1000>;
- clocks = <&rpmcc RPM_QDSS_CLK>;
- clock-names = "apb_pclk";
- arm,cti-v8-arch;
- cpu = <&CPU1>;
- arm,cs-dev-assoc = <&etm1>;
+};
+This example will result in the same internal structure as e.g.(2)
+The arm,cti-v8-arch property declares this as a v8 CTI, the cpu property must +be present, and a single arm,cs-dev-assoc may be present to define an attached +ETM. No additional trig-conns nodes are permitted. The driver will build a +connection model according to architectural requirements. This will include +a filter on the CPU dbgreq signal as described above.
s/dbgreq/DBGREQ
+All the CTI devices are associated with a CTM. On many systems there will be a +single effective CTM (one CTM, or multiple CTMs all interconnected), but it is +possible that systems can have nets of CTIs+CTM that are not interconnected by +a CTM. On these systems a CTM index is declared to associate CTI devices that +are interconnected via the CTM.
- e.g.
- arm,cti-ctm-id=<2>
+CTI devices with the same CTM ID are considered connected by the CTM. If this +parameter is absent then all CTIs are considered interconnected by the same +CTM.
+*Summary of CTI required properties:
- compatible : should be "arm,coresight-cti"; supplemented with
"arm,primecell" since this driver is using the AMBA bus
interface.
- reg: physical base address and length of the register
set(s) of the component.
- clocks: the clocks associated to this component.
- clock-names: the name of the clocks referenced by the code.
Since we are using the AMBA framework, the name of the clock
providing the interconnect should be "apb_pclk", and some
coresight blocks also have an additional clock "atclk", which
clocks the core of that coresight component. The latter clock
is optional.
+*Summary of CTI optional properties:
- trig-conns: defines a connection node between CTI and a component.
Component may be a CPU, CoreSight device, any other hardware device
or simple external IO lines.
- arm,cti-v8-arch: Declares this CTI device as a v8 architecturally
defined device. Use in CTI base node only, no additional trig-conns
nodes permitted if this is declared.
- cpu: defines a phandle reference to an associated CPU. Used in
trig-conns node, or in CTI base node when arm,cti-v8-arch present.
- arm,cs-dev-assoc: defines a phandle reference to an associated
CoreSight trace device. When the associated trace device is enabled,
then the respective CTI will be enabled. Use in a trig-conns node,
or in CTI base node when arm,cti-v8-arch present. If the associated
device has not been registered then the node name will be stored as
the connection name for later resolution. If the associated device is
not a CoreSight device or not registered then the node name will
remain the connection name and automatic enabling will not occur.
- arm,cti-ctm-id: Defines the interconnecting CTM for this device.
Use in CTI base node.
- Properties valid in the trig-conns node:
* arm,trig-in-sigs: List of CTI trigger in signals in use by a
trig-conns node.
* arm,trig-in-types: List of types for the CTI trigger in
signals. Types in this array match to the corresponding signal
in the arm,trig-in-sigs array. If the -types array is smaller,
or omitted completely, then the types will default to GEN_IO.
* arm,trig-out-sigs: List of CTI trigger out signals in use by a
trig-conns node.
* arm,trig-out-types: List of types for the CTI trigger out
signals. Types in this array match to the corresponding signal
in the arm,trig-out-sigs array. If the "-types" array is
smaller, or omitted completely, then the types will default
to GEN_IO.
* arm-trig-filters: List of CTI trigger out signals that will be
blocked from becoming active, unless filtering is disabled on
the driver.
*arm,trig-conn-name: defines a connection name that will be
displayed, if not overridden by the name of associated device
from arm,cs-dev-assoc or the CPU. Principle use for CTI that
are connected to non-CoreSight devices, or external IO.
The above lines need to be shifted to the right by one to align with "arm".
+e.g.(5) Combined examples showing all properties:
+a) Minimum CTI definition +cti0: cti@20020000 {
- compatible = "arm,coresight-cti", "arm,primecell";
- reg = <0x20020000 0x1000>;
- clocks = <&soc_smc50mhz>;
- clock-names = "apb_pclk";
+};
+b) v8 architecturally defined CTI - CPU + ETM connections. +cti@859000 {
- compatible = "arm,coresight-cti", "arm,primecell";
- reg = <0x859000 0x1000>;
- clocks = <&rpmcc RPM_QDSS_CLK>;
- clock-names = "apb_pclk";
- arm,cti-v8-arch;
- cpu = <&CPU1>;
- arm,cs-dev-assoc = <&etm1>;
+};
+c) Implementation defined CTI - CPU + ETM connections. +cti@858000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x858000 0x1000>;
clocks = <&rpmcc RPM_QDSS_CLK>;
clock-names = "apb_pclk";
trig-conns@0 {
arm,trig-in-sigs = <4 5 6 7>;
arm,trig-in-types = <ETM_EXTOUT
ETM_EXTOUT
ETM_EXTOUT
ETM_EXTOUT>;
arm,trig-out-sigs = <4 5 6 7>;
arm,trig-out-types = <ETM_EXTIN
ETM_EXTIN
ETM_EXTIN
ETM_EXTIN>;
arm,cs-dev-assoc = <&etm0>;
};
trig-conns@1 {
cpu = <&CPU0>;
arm,trig-in-sigs = <0 1>;
arm,trig-in-types = <PE_DBGTRIGGER
PE_PMUIRQ>;
arm,trig-out-sigs=<0 1 2 >;
arm,trig-out-types = <PE_EDBGREQ
PE_DBGRESTART
PE_CTIIRQ>;
arm,trig-filters = <0>;
};
arm,cti-ctm-id = <1>;
+};
+d) Implementation defined CTI - Coresight STM, ETF, ETR connections. +cti@20020000 { /*Juno sys_cti_0 */
- compatible = "arm,coresight-cti", "arm,primecell";
- reg = <0 0x20020000 0 0x1000>;
- clocks = <&soc_smc50mhz>;
- clock-names = "apb_pclk";
- power-domains = <&scpi_devpd 0>;
- trig-conns@0 {
arm,trig-in-sigs=<2 3>;
arm,trig-in-types=<SNK_FULL
SNK_ACQCOMP>;
arm,trig-out-sigs=<0 1>;
arm,trig-out-types=<SNK_FLUSHIN
SNK_TRIGIN>;
arm,cs-dev-assoc = <&etr_sys>;
- };
- trig-conns@1 {
arm,trig-in-sigs=<0 1>;
arm,trig-in-types=<SNK_FULL
SNK_ACQCOMP>;
arm,trig-out-sigs=<7 6>;
arm,trig-out-types=<SNK_FLUSHIN
SNK_TRIGIN>;
arm,cs-dev-assoc = <&etf_sys0>;
- };
- trig-conns@2 {
arm,trig-in-sigs=<4 5 6 7>;
arm,trig-in-types=<STM_TOUT_SPTE
STM_TOUT_SW
STM_TOUT_HETE
STM_ASYNCOUT>;
arm,trig-out-sigs=<4 5>;
arm,trig-out-types=<STM_HWEVENT
STM_HWEVENT>;
arm,cs-dev-assoc = <&stm_sys>;
- };
- trig-conns@3 {
arm,trig-out-sigs=<2 3>;
arm,trig-out-types=<SNK_FLUSHIN
SNK_TRIGIN>;
arm,cs-dev-assoc = <&tpiu_sys>;
- };
+};
+e) Implementation defined CTI - none CoreSight component connections. +cti@20110000 { /* Juno sys_cti_1 */
- compatible = "arm,coresight-cti", "arm,primecell";
- reg = <0 0x20110000 0 0x1000>;
- clocks = <&soc_smc50mhz>;
- clock-names = "apb_pclk";
- power-domains = <&scpi_devpd 0>;
- trig-conns@0 {
arm,trig-in-sigs=<0>;
arm,trig-in-types=<GEN_INTREQ>;
arm,trig-out-sigs=<0>;
arm,trig-out-types=<GEN_HALTREQ>;
arm,trig-conn-name = "sys_profiler";
- };
- trig-conns@1 {
arm,trig-out-sigs=<2 3>;
arm,trig-out-types=<GEN_HALTREQ GEN_RESTARTREQ>;
arm,trig-conn-name = "watchdog";
- };
- trig-conns@2 {
arm,trig-out-sigs=<1 6>;
arm,trig-out-types=<GEN_HALTREQ GEN_RESTARTREQ>;
arm,trig-conn-name = "g_counter";
- };
+}; diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt index fcc3bacfd8bc..a24713e48304 100644 --- a/Documentation/devicetree/bindings/arm/coresight.txt +++ b/Documentation/devicetree/bindings/arm/coresight.txt @@ -45,6 +45,10 @@ its hardware characteristcs. - Coresight Address Translation Unit (CATU) "arm,coresight-catu", "arm,primecell";
- Coresight Cross Trigger Interface (CTI):
"arm,coresight-cti", "arm,primecell";
See coresight-ect-cti.txt for full CTI definitions.
- reg: physical base address and length of the register set(s) of the component.
@@ -72,6 +76,9 @@ its hardware characteristcs.
- reg-names: the only acceptable values are "stm-base" and "stm-stimulus-base", each corresponding to the areas defined in "reg".
+* Required properties for Coresight Cross Trigger Interface (CTI)
See coresight-ect-cti.txt for full CTI definitions.
- Required properties for devices that don't show up on the AMBA bus, such as non-configurable replicators and non-configurable funnels:
diff --git a/MAINTAINERS b/MAINTAINERS index 783569e3c4b4..a81f3bd8340a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1582,10 +1582,12 @@ R: Suzuki K Poulose suzuki.poulose@arm.com L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: drivers/hwtracing/coresight/* +F: include/dt-bindings/arm/coresight-cti-dt.h F: Documentation/trace/coresight.txt F: Documentation/trace/coresight-cpu-debug.txt F: Documentation/devicetree/bindings/arm/coresight.txt F: Documentation/devicetree/bindings/arm/coresight-cpu-debug.txt +F: Documentation/devicetree/bindings/arm/coresight-ect-cti.txt F: Documentation/ABI/testing/sysfs-bus-coresight-devices-* F: tools/perf/arch/arm/util/pmu.c F: tools/perf/arch/arm/util/auxtrace.c diff --git a/include/dt-bindings/arm/coresight-cti-dt.h b/include/dt-bindings/arm/coresight-cti-dt.h new file mode 100644 index 000000000000..88580b5a0388 --- /dev/null +++ b/include/dt-bindings/arm/coresight-cti-dt.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- This header provides constants for the defined trigger signal
- types on CoreSight CTI.
- */
+#ifndef _DT_BINDINGS_ARM_CORESIGHT_CTI_DT_H +#define _DT_BINDINGS_ARM_CORESIGHT_CTI_DT_H
+#define GEN_IO 0 +#define GEN_INTREQ 1 +#define GEN_INTACK 2 +#define GEN_HALTREQ 3 +#define GEN_RESTARTREQ 4 +#define PE_EDBGREQ 5 +#define PE_DBGRESTART 6 +#define PE_CTIIRQ 7 +#define PE_PMUIRQ 8 +#define PE_DBGTRIGGER 9 +#define ETM_EXTOUT 10 +#define ETM_EXTIN 11 +#define SNK_FULL 12 +#define SNK_ACQCOMP 13 +#define SNK_FLUSHCOMP 14 +#define SNK_FLUSHIN 15 +#define SNK_TRIGIN 16 +#define STM_ASYNCOUT 17 +#define STM_TOUT_SPTE 18 +#define STM_TOUT_SW 19 +#define STM_TOUT_HETE 20 +#define STM_HWEVENT 21 +#define ELA_TSTART 22 +#define ELA_TSTOP 23 +#define ELA_DBGREQ 24
+#endif /*_DT_BINDINGS_ARM_CORESIGHT_CTI_DT_H */
2.17.1
The v8 architecture defines the relationship between a PE, its optional ETM and a CTI. Unlike non-architectural CTIs which are implementation defined, this has a fixed set of connections which can therefore be represented as a simple tag in the device tree.
This patch defines the tags needed to create an entry for this PE/ETM/CTI relationship, and provides functionality to implement the connection model in the CTI driver.
Signed-off-by: Mike Leach mike.leach@linaro.org --- .../coresight/coresight-cti-platform.c | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c index eb4f8a835c10..3ee5b8f8d245 100644 --- a/drivers/hwtracing/coresight/coresight-cti-platform.c +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -3,11 +3,159 @@ * Copyright (c) 2019, The Linux Foundation. All rights reserved. */
+#include <dt-bindings/arm/coresight-cti-dt.h> #include <linux/of.h>
#include "coresight-cti.h"
+/* Number of CTI signals in the v8 architecturally defined connection */ +#define NR_V8PE_IN_SIGS 2 +#define NR_V8PE_OUT_SIGS 3 +#define NR_V8ETM_INOUT_SIGS 4 + +/* CTI device tree connection property keywords */ +#define CTI_DT_V8ARCH "arm,cti-v8-arch" +#define CTI_DT_CSDEV_ASSOC "arm,cs-dev-assoc" + +/* + * Find a registered coresight device from a device fwnode. + * The node info is associated with the AMBA parent, but the + * csdev keeps a copy so iterate round the coresight bus to + * find the device. + */ +static struct coresight_device * +cti_get_assoc_csdev_by_fwnode(struct fwnode_handle *r_fwnode) +{ + struct device *dev; + struct coresight_device *csdev = NULL; + + dev = bus_find_device_by_fwnode(&coresight_bustype, r_fwnode); + if (dev) { + csdev = to_coresight_device(dev); + put_device(dev); + } + return csdev; +} + #ifdef CONFIG_OF +/* + * CTI can be bound to a CPU, or a system device. + * CPU can be declared at the device top level or in a connections node + * so need to check relative to node not device. + */ +static int of_cti_get_cpu_at_node(const struct device_node *node) +{ + int cpu; + struct device_node *dn; + + dn = of_parse_phandle(node, "cpu", 0); + /* CTI affinity defaults to no cpu */ + if (!dn) + return -1; + cpu = of_cpu_node_to_id(dn); + of_node_put(dn); + + /* No Affinity if no cpu nodes are found */ + return (cpu < 0) ? -1 : cpu; +} + +static int of_cti_create_v8_etm_connection(struct device *dev, + struct cti_drvdata *drvdata, + struct device_node *np) +{ + int ret = -ENOMEM, i; + struct device_node *cs_np; + const char *assoc_name = NULL; + struct coresight_device *csdev; + struct fwnode_handle *r_fwnode; + struct cti_trig_con *tc = NULL; + + /* Can optionally have an etm node - return if not */ + cs_np = of_parse_phandle(np, CTI_DT_CSDEV_ASSOC, 0); + if (!cs_np) + return 0; + + /* allocate memory */ + tc = cti_allocate_trig_con(dev, NR_V8ETM_INOUT_SIGS, + NR_V8ETM_INOUT_SIGS); + if (!tc) + goto of_create_v8_etm_out; + + /* build connection data */ + tc->con_in->used_mask = 0xF0; /* sigs <4,5,6,7> */ + tc->con_out->used_mask = 0xF0; /* sigs <4,5,6,7> */ + + for (i = 0; i < NR_V8ETM_INOUT_SIGS; i++) { + tc->con_in->sig_types[i] = ETM_EXTOUT; + tc->con_out->sig_types[i] = ETM_EXTIN; + } + + r_fwnode = of_fwnode_handle(cs_np); + csdev = cti_get_assoc_csdev_by_fwnode(r_fwnode); + if (csdev) + assoc_name = dev_name(&csdev->dev); + else + assoc_name = cs_np->full_name; + ret = cti_add_connection_entry(dev, drvdata, tc, csdev, assoc_name); + +of_create_v8_etm_out: + of_node_put(cs_np); + return ret; +} + +/* + * Create an architecturally defined v8 connection + * must have a cpu, can have an ETM. + */ +static int of_cti_create_v8_connections(struct device *dev, + struct cti_drvdata *drvdata, + struct device_node *np) +{ + struct cti_device *cti_dev = &drvdata->ctidev; + struct cti_trig_con *tc = NULL; + int cpuid = 0; + char cpu_name_str[16]; + int ret = -ENOMEM; + + /* Must have a cpu node */ + cpuid = of_cti_get_cpu_at_node(np); + if (cpuid < 0) { + dev_warn(dev, "CTI v8 DT binding no cpu\n"); + return -EINVAL; + } + cti_dev->cpu = cpuid; + + /* Allocate the v8 cpu connection memory */ + tc = cti_allocate_trig_con(dev, NR_V8PE_IN_SIGS, NR_V8PE_OUT_SIGS); + if (!tc) + goto of_create_v8_out; + + /* Set the v8 PE CTI connection data */ + tc->con_in->used_mask = 0x3; /* sigs <0 1> */ + tc->con_in->sig_types[0] = PE_DBGTRIGGER; + tc->con_in->sig_types[1] = PE_PMUIRQ; + tc->con_out->used_mask = 0x7; /* sigs <0 1 2 > */ + tc->con_out->sig_types[0] = PE_EDBGREQ; + tc->con_out->sig_types[1] = PE_DBGRESTART; + tc->con_out->sig_types[2] = PE_CTIIRQ; + scnprintf(cpu_name_str, sizeof(cpu_name_str), "cpu%d", cpuid); + + ret = cti_add_connection_entry(dev, drvdata, tc, NULL, cpu_name_str); + if (ret) + goto of_create_v8_out; + + /* Create the v8 ETM associated connection */ + ret = of_cti_create_v8_etm_connection(dev, drvdata, np); + if (ret) + goto of_create_v8_out; + + /* filter pe_edbgreq - PE trigout sig <0> */ + drvdata->config.trig_out_filter |= 0x1; + +of_create_v8_out: + return ret; +} + /* get the hardware configuration & connection data. */ int of_cti_get_hw_data(struct device *dev, struct device_node *np, @@ -16,6 +164,13 @@ int of_cti_get_hw_data(struct device *dev, int rc = 0; struct cti_device *cti_dev = &drvdata->ctidev;
+ /* check for a v8 architectural CTI device */ + if (of_property_read_bool(np, CTI_DT_V8ARCH)) { + rc = of_cti_create_v8_connections(dev, drvdata, np); + if (rc) + return rc; + } + /* if no connections, just add a single default based on max IN-OUT */ if (cti_dev->nr_trig_con == 0) rc = cti_add_default_connection(dev, drvdata);
On Mon, Aug 19, 2019 at 10:13:52PM +0100, Mike Leach wrote:
The v8 architecture defines the relationship between a PE, its optional ETM and a CTI. Unlike non-architectural CTIs which are implementation defined, this has a fixed set of connections which can therefore be represented as a simple tag in the device tree.
This patch defines the tags needed to create an entry for this PE/ETM/CTI relationship, and provides functionality to implement the connection model in the CTI driver.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../coresight/coresight-cti-platform.c | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c index eb4f8a835c10..3ee5b8f8d245 100644 --- a/drivers/hwtracing/coresight/coresight-cti-platform.c +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -3,11 +3,159 @@
- Copyright (c) 2019, The Linux Foundation. All rights reserved.
*/ +#include <dt-bindings/arm/coresight-cti-dt.h> #include <linux/of.h> #include "coresight-cti.h" +/* Number of CTI signals in the v8 architecturally defined connection */ +#define NR_V8PE_IN_SIGS 2 +#define NR_V8PE_OUT_SIGS 3 +#define NR_V8ETM_INOUT_SIGS 4
+/* CTI device tree connection property keywords */ +#define CTI_DT_V8ARCH "arm,cti-v8-arch" +#define CTI_DT_CSDEV_ASSOC "arm,cs-dev-assoc"
+/*
- Find a registered coresight device from a device fwnode.
- The node info is associated with the AMBA parent, but the
- csdev keeps a copy so iterate round the coresight bus to
- find the device.
- */
+static struct coresight_device * +cti_get_assoc_csdev_by_fwnode(struct fwnode_handle *r_fwnode) +{
- struct device *dev;
- struct coresight_device *csdev = NULL;
- dev = bus_find_device_by_fwnode(&coresight_bustype, r_fwnode);
- if (dev) {
csdev = to_coresight_device(dev);
put_device(dev);
- }
- return csdev;
+}
#ifdef CONFIG_OF +/*
- CTI can be bound to a CPU, or a system device.
- CPU can be declared at the device top level or in a connections node
- so need to check relative to node not device.
- */
+static int of_cti_get_cpu_at_node(const struct device_node *node) +{
- int cpu;
- struct device_node *dn;
- dn = of_parse_phandle(node, "cpu", 0);
- /* CTI affinity defaults to no cpu */
- if (!dn)
return -1;
- cpu = of_cpu_node_to_id(dn);
- of_node_put(dn);
- /* No Affinity if no cpu nodes are found */
- return (cpu < 0) ? -1 : cpu;
+}
+static int of_cti_create_v8_etm_connection(struct device *dev,
struct cti_drvdata *drvdata,
struct device_node *np)
+{
- int ret = -ENOMEM, i;
- struct device_node *cs_np;
- const char *assoc_name = NULL;
- struct coresight_device *csdev;
- struct fwnode_handle *r_fwnode;
- struct cti_trig_con *tc = NULL;
- /* Can optionally have an etm node - return if not */
- cs_np = of_parse_phandle(np, CTI_DT_CSDEV_ASSOC, 0);
extra space after "np,"
- if (!cs_np)
return 0;
- /* allocate memory */
- tc = cti_allocate_trig_con(dev, NR_V8ETM_INOUT_SIGS,
NR_V8ETM_INOUT_SIGS);
- if (!tc)
goto of_create_v8_etm_out;
- /* build connection data */
- tc->con_in->used_mask = 0xF0; /* sigs <4,5,6,7> */
- tc->con_out->used_mask = 0xF0; /* sigs <4,5,6,7> */
- for (i = 0; i < NR_V8ETM_INOUT_SIGS; i++) {
tc->con_in->sig_types[i] = ETM_EXTOUT;
tc->con_out->sig_types[i] = ETM_EXTIN;
- }
So far I understand that connection names (and the processing going with them) has been centered on the CTI itself. Either the above is a mistake and should read: tc->con_in->sig_types[i] = ETM_EXTIN; tc->con_out->sig_types[i] = ETM_EXTOUT;
or the logic is that ETM_EXTOUT becomes an input for the CTI. If so please add a comment to make it clear that a CTI IN is an ETM OUT and vice versa. Otherwise I can already see patches to correct the "bug" accumulating in my inbox.
- r_fwnode = of_fwnode_handle(cs_np);
- csdev = cti_get_assoc_csdev_by_fwnode(r_fwnode);
- if (csdev)
assoc_name = dev_name(&csdev->dev);
- else
assoc_name = cs_np->full_name;
I understand what is happening here only because I am familiar with CS and the chicken-and-egg conundrum inherent to device discovery. Please add a comment describing what is happening and exactly where, i.e function name, things are fixed in the future.
- ret = cti_add_connection_entry(dev, drvdata, tc, csdev, assoc_name);
+of_create_v8_etm_out:
- of_node_put(cs_np);
- return ret;
+}
+/*
- Create an architecturally defined v8 connection
- must have a cpu, can have an ETM.
- */
+static int of_cti_create_v8_connections(struct device *dev,
struct cti_drvdata *drvdata,
struct device_node *np)
+{
- struct cti_device *cti_dev = &drvdata->ctidev;
- struct cti_trig_con *tc = NULL;
- int cpuid = 0;
- char cpu_name_str[16];
- int ret = -ENOMEM;
- /* Must have a cpu node */
- cpuid = of_cti_get_cpu_at_node(np);
- if (cpuid < 0) {
dev_warn(dev, "CTI v8 DT binding no cpu\n");
return -EINVAL;
- }
- cti_dev->cpu = cpuid;
- /* Allocate the v8 cpu connection memory */
- tc = cti_allocate_trig_con(dev, NR_V8PE_IN_SIGS, NR_V8PE_OUT_SIGS);
- if (!tc)
goto of_create_v8_out;
- /* Set the v8 PE CTI connection data */
- tc->con_in->used_mask = 0x3; /* sigs <0 1> */
- tc->con_in->sig_types[0] = PE_DBGTRIGGER;
- tc->con_in->sig_types[1] = PE_PMUIRQ;
- tc->con_out->used_mask = 0x7; /* sigs <0 1 2 > */
- tc->con_out->sig_types[0] = PE_EDBGREQ;
- tc->con_out->sig_types[1] = PE_DBGRESTART;
- tc->con_out->sig_types[2] = PE_CTIIRQ;
- scnprintf(cpu_name_str, sizeof(cpu_name_str), "cpu%d", cpuid);
- ret = cti_add_connection_entry(dev, drvdata, tc, NULL, cpu_name_str);
- if (ret)
goto of_create_v8_out;
- /* Create the v8 ETM associated connection */
- ret = of_cti_create_v8_etm_connection(dev, drvdata, np);
- if (ret)
goto of_create_v8_out;
- /* filter pe_edbgreq - PE trigout sig <0> */
- drvdata->config.trig_out_filter |= 0x1;
+of_create_v8_out:
- return ret;
+}
/* get the hardware configuration & connection data. */ int of_cti_get_hw_data(struct device *dev, struct device_node *np, @@ -16,6 +164,13 @@ int of_cti_get_hw_data(struct device *dev, int rc = 0; struct cti_device *cti_dev = &drvdata->ctidev;
- /* check for a v8 architectural CTI device */
- if (of_property_read_bool(np, CTI_DT_V8ARCH)) {
rc = of_cti_create_v8_connections(dev, drvdata, np);
Please refer to the new comment I posted in patch 01 about making functions generic to lessen the burden of adding ACPI support.
Thanks, Mathieu
if (rc)
return rc;
- }
- /* if no connections, just add a single default based on max IN-OUT */ if (cti_dev->nr_trig_con == 0) rc = cti_add_default_connection(dev, drvdata);
-- 2.17.1
Hi Mathieu,
New patch has extended comments per your suggestion. As mentioned - this patch and the next re-written to maximise use of fwnode functionality.
Thanks
Mike
On Tue, 1 Oct 2019 at 20:47, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Mon, Aug 19, 2019 at 10:13:52PM +0100, Mike Leach wrote:
The v8 architecture defines the relationship between a PE, its optional ETM and a CTI. Unlike non-architectural CTIs which are implementation defined, this has a fixed set of connections which can therefore be represented as a simple tag in the device tree.
This patch defines the tags needed to create an entry for this PE/ETM/CTI relationship, and provides functionality to implement the connection model in the CTI driver.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../coresight/coresight-cti-platform.c | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c index eb4f8a835c10..3ee5b8f8d245 100644 --- a/drivers/hwtracing/coresight/coresight-cti-platform.c +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -3,11 +3,159 @@
- Copyright (c) 2019, The Linux Foundation. All rights reserved.
*/
+#include <dt-bindings/arm/coresight-cti-dt.h> #include <linux/of.h>
#include "coresight-cti.h"
+/* Number of CTI signals in the v8 architecturally defined connection */ +#define NR_V8PE_IN_SIGS 2 +#define NR_V8PE_OUT_SIGS 3 +#define NR_V8ETM_INOUT_SIGS 4
+/* CTI device tree connection property keywords */ +#define CTI_DT_V8ARCH "arm,cti-v8-arch" +#define CTI_DT_CSDEV_ASSOC "arm,cs-dev-assoc"
+/*
- Find a registered coresight device from a device fwnode.
- The node info is associated with the AMBA parent, but the
- csdev keeps a copy so iterate round the coresight bus to
- find the device.
- */
+static struct coresight_device * +cti_get_assoc_csdev_by_fwnode(struct fwnode_handle *r_fwnode) +{
struct device *dev;
struct coresight_device *csdev = NULL;
dev = bus_find_device_by_fwnode(&coresight_bustype, r_fwnode);
if (dev) {
csdev = to_coresight_device(dev);
put_device(dev);
}
return csdev;
+}
#ifdef CONFIG_OF +/*
- CTI can be bound to a CPU, or a system device.
- CPU can be declared at the device top level or in a connections node
- so need to check relative to node not device.
- */
+static int of_cti_get_cpu_at_node(const struct device_node *node) +{
int cpu;
struct device_node *dn;
dn = of_parse_phandle(node, "cpu", 0);
/* CTI affinity defaults to no cpu */
if (!dn)
return -1;
cpu = of_cpu_node_to_id(dn);
of_node_put(dn);
/* No Affinity if no cpu nodes are found */
return (cpu < 0) ? -1 : cpu;
+}
+static int of_cti_create_v8_etm_connection(struct device *dev,
struct cti_drvdata *drvdata,
struct device_node *np)
+{
int ret = -ENOMEM, i;
struct device_node *cs_np;
const char *assoc_name = NULL;
struct coresight_device *csdev;
struct fwnode_handle *r_fwnode;
struct cti_trig_con *tc = NULL;
/* Can optionally have an etm node - return if not */
cs_np = of_parse_phandle(np, CTI_DT_CSDEV_ASSOC, 0);
extra space after "np,"
if (!cs_np)
return 0;
/* allocate memory */
tc = cti_allocate_trig_con(dev, NR_V8ETM_INOUT_SIGS,
NR_V8ETM_INOUT_SIGS);
if (!tc)
goto of_create_v8_etm_out;
/* build connection data */
tc->con_in->used_mask = 0xF0; /* sigs <4,5,6,7> */
tc->con_out->used_mask = 0xF0; /* sigs <4,5,6,7> */
for (i = 0; i < NR_V8ETM_INOUT_SIGS; i++) {
tc->con_in->sig_types[i] = ETM_EXTOUT;
tc->con_out->sig_types[i] = ETM_EXTIN;
}
So far I understand that connection names (and the processing going with them) has been centered on the CTI itself. Either the above is a mistake and should read: tc->con_in->sig_types[i] = ETM_EXTIN; tc->con_out->sig_types[i] = ETM_EXTOUT;
or the logic is that ETM_EXTOUT becomes an input for the CTI. If so please add a comment to make it clear that a CTI IN is an ETM OUT and vice versa. Otherwise I can already see patches to correct the "bug" accumulating in my inbox.
r_fwnode = of_fwnode_handle(cs_np);
csdev = cti_get_assoc_csdev_by_fwnode(r_fwnode);
if (csdev)
assoc_name = dev_name(&csdev->dev);
else
assoc_name = cs_np->full_name;
I understand what is happening here only because I am familiar with CS and the chicken-and-egg conundrum inherent to device discovery. Please add a comment describing what is happening and exactly where, i.e function name, things are fixed in the future.
ret = cti_add_connection_entry(dev, drvdata, tc, csdev, assoc_name);
+of_create_v8_etm_out:
of_node_put(cs_np);
return ret;
+}
+/*
- Create an architecturally defined v8 connection
- must have a cpu, can have an ETM.
- */
+static int of_cti_create_v8_connections(struct device *dev,
struct cti_drvdata *drvdata,
struct device_node *np)
+{
struct cti_device *cti_dev = &drvdata->ctidev;
struct cti_trig_con *tc = NULL;
int cpuid = 0;
char cpu_name_str[16];
int ret = -ENOMEM;
/* Must have a cpu node */
cpuid = of_cti_get_cpu_at_node(np);
if (cpuid < 0) {
dev_warn(dev, "CTI v8 DT binding no cpu\n");
return -EINVAL;
}
cti_dev->cpu = cpuid;
/* Allocate the v8 cpu connection memory */
tc = cti_allocate_trig_con(dev, NR_V8PE_IN_SIGS, NR_V8PE_OUT_SIGS);
if (!tc)
goto of_create_v8_out;
/* Set the v8 PE CTI connection data */
tc->con_in->used_mask = 0x3; /* sigs <0 1> */
tc->con_in->sig_types[0] = PE_DBGTRIGGER;
tc->con_in->sig_types[1] = PE_PMUIRQ;
tc->con_out->used_mask = 0x7; /* sigs <0 1 2 > */
tc->con_out->sig_types[0] = PE_EDBGREQ;
tc->con_out->sig_types[1] = PE_DBGRESTART;
tc->con_out->sig_types[2] = PE_CTIIRQ;
scnprintf(cpu_name_str, sizeof(cpu_name_str), "cpu%d", cpuid);
ret = cti_add_connection_entry(dev, drvdata, tc, NULL, cpu_name_str);
if (ret)
goto of_create_v8_out;
/* Create the v8 ETM associated connection */
ret = of_cti_create_v8_etm_connection(dev, drvdata, np);
if (ret)
goto of_create_v8_out;
/* filter pe_edbgreq - PE trigout sig <0> */
drvdata->config.trig_out_filter |= 0x1;
+of_create_v8_out:
return ret;
+}
/* get the hardware configuration & connection data. */ int of_cti_get_hw_data(struct device *dev, struct device_node *np, @@ -16,6 +164,13 @@ int of_cti_get_hw_data(struct device *dev, int rc = 0; struct cti_device *cti_dev = &drvdata->ctidev;
/* check for a v8 architectural CTI device */
if (of_property_read_bool(np, CTI_DT_V8ARCH)) {
rc = of_cti_create_v8_connections(dev, drvdata, np);
Please refer to the new comment I posted in patch 01 about making functions generic to lessen the burden of adding ACPI support.
Thanks, Mathieu
if (rc)
return rc;
}
/* if no connections, just add a single default based on max IN-OUT */ if (cti_dev->nr_trig_con == 0) rc = cti_add_default_connection(dev, drvdata);
-- 2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
Adds support for CTIs whose connections are implementation defined at hardware design time, and not constrained by v8 architecture.
These CTIs have no standard connection setup, all the settings have to be defined in the device tree files. The patch creates a set of connections and trigger signals based on the information provided.
Signed-off-by: Mike Leach mike.leach@linaro.org --- .../coresight/coresight-cti-platform.c | 209 +++++++++++++++++- 1 file changed, 204 insertions(+), 5 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c index 3ee5b8f8d245..b7649f75f08b 100644 --- a/drivers/hwtracing/coresight/coresight-cti-platform.c +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -13,9 +13,19 @@ #define NR_V8PE_OUT_SIGS 3 #define NR_V8ETM_INOUT_SIGS 4
+/* CTI device tree trigger connection node keyword */ +#define CTI_DT_CONNS "trig-conns" + /* CTI device tree connection property keywords */ #define CTI_DT_V8ARCH "arm,cti-v8-arch" #define CTI_DT_CSDEV_ASSOC "arm,cs-dev-assoc" +#define CTI_DT_CTM_ID "arm,cti-ctm-id" +#define CTI_DT_TRIGIN_SIGS "arm,trig-in-sigs" +#define CTI_DT_TRIGOUT_SIGS "arm,trig-out-sigs" +#define CTI_DT_TRIGIN_TYPES "arm,trig-in-types" +#define CTI_DT_TRIGOUT_TYPES "arm,trig-out-types" +#define CTI_DT_FILTER_OUT_SIGS "arm,trig-filters" +#define CTI_DT_CONN_NAME "arm,trig-conn-name"
/* * Find a registered coresight device from a device fwnode. @@ -156,6 +166,188 @@ static int of_cti_create_v8_connections(struct device *dev, return ret; }
+ +static int of_count_sig_elements(const struct device_node *np, + const char *name) +{ + int nr_elem = of_property_count_elems_of_size(np, name, 4); + + return (nr_elem < 0 ? 0 : nr_elem); +} + +static int of_cti_read_trig_group(struct cti_trig_grp *tgrp, + struct device_node *np, + const char *grp_name) +{ + int items = tgrp->nr_sigs, err = 0; + u32 value, pidx; + + if (!items) + return 0; + + /* set the signal usage mask */ + for (pidx = 0; pidx < items; pidx++) { + err = of_property_read_u32_index(np, grp_name, pidx, &value); + if (err) + return err; + tgrp->used_mask |= BIT(value); + } + return 0; +} + +static int of_cti_read_trig_types(struct cti_trig_grp *tgrp, + struct device_node *np, + const char *type_name) +{ + int items, used = 0, err = 0, nr_sigs; + u32 value, i; + + /* allocate an array according to number of signals in connection */ + nr_sigs = tgrp->nr_sigs; + if (!nr_sigs) + return 0; + + /* see if any types have been included in the device description */ + items = of_count_sig_elements(np, type_name); + if (items > nr_sigs) + return -EINVAL; + + /* + * Match type id to signal index, 1st type to 1st index etc. + * If fewer types than signals default remainer to GEN_IO. + */ + for (i = 0; i < nr_sigs; i++) { + if (used < items) { + err = of_property_read_u32_index(np, type_name, + i, &value); + if (!err) + tgrp->sig_types[i] = value; + else + tgrp->sig_types[i] = GEN_IO; + used++; + } else + tgrp->sig_types[i] = GEN_IO; + } + return 0; +} + +static int of_cti_process_filter_sigs(struct cti_drvdata *drvdata, + struct device_node *np) +{ + struct cti_trig_grp *tg = NULL; + int err = 0, nr_filter_sigs; + + nr_filter_sigs = of_count_sig_elements(np, CTI_DT_FILTER_OUT_SIGS); + if (nr_filter_sigs == 0) + return 0; + + if (nr_filter_sigs > drvdata->config.nr_trig_max) + return -EINVAL; + + tg = kzalloc(sizeof(*tg), GFP_KERNEL); + if (!tg) + return -ENOMEM; + + err = of_cti_read_trig_group(tg, np, CTI_DT_FILTER_OUT_SIGS); + if (!err) + drvdata->config.trig_out_filter |= tg->used_mask; + + kfree(tg); + return err; +} + +static int of_cti_create_connection(struct device *dev, + struct cti_drvdata *drvdata, + struct device_node *np) +{ + struct cti_trig_con *tc = NULL; + int cpuid = -1, err = 0; + struct device_node *cs_np = NULL; + struct coresight_device *csdev = NULL; + const char *assoc_name = "unknown"; + char cpu_name_str[16]; + struct fwnode_handle *r_fwnode; + int nr_sigs_in, nr_sigs_out; + + /* look to see how many in and out signals we have */ + nr_sigs_in = of_count_sig_elements(np, CTI_DT_TRIGIN_SIGS); + nr_sigs_out = of_count_sig_elements(np, CTI_DT_TRIGOUT_SIGS); + + if ((nr_sigs_in > drvdata->config.nr_trig_max) || + (nr_sigs_out > drvdata->config.nr_trig_max)) + return -EINVAL; + + tc = cti_allocate_trig_con(dev, nr_sigs_in, nr_sigs_out); + if (!tc) + return -ENOMEM; + + /* look for the signals properties. */ + err = of_cti_read_trig_group(tc->con_in, np, CTI_DT_TRIGIN_SIGS); + if (err) + goto of_create_con_err; + + err = of_cti_read_trig_types(tc->con_in, np, CTI_DT_TRIGIN_TYPES); + if (err) + goto of_create_con_err; + + err = of_cti_read_trig_group(tc->con_out, np, CTI_DT_TRIGOUT_SIGS); + if (err) + goto of_create_con_err; + + err = of_cti_read_trig_types(tc->con_out, np, CTI_DT_TRIGOUT_TYPES); + if (err) + goto of_create_con_err; + + err = of_cti_process_filter_sigs(drvdata, np); + if (err) + goto of_create_con_err; + + /* read the connection name if set - may be overridden by later */ + of_property_read_string(np, CTI_DT_CONN_NAME, &assoc_name); + + /* associated cpu ? */ + cpuid = of_cti_get_cpu_at_node(np); + if (cpuid >= 0) { + drvdata->ctidev.cpu = cpuid; + scnprintf(cpu_name_str, sizeof(cpu_name_str), "cpu%d", cpuid); + assoc_name = cpu_name_str; + } else { + /* associated device ? */ + cs_np = of_parse_phandle(np, CTI_DT_CSDEV_ASSOC, 0); + if (cs_np) { + r_fwnode = of_fwnode_handle(cs_np); + csdev = cti_get_assoc_csdev_by_fwnode(r_fwnode); + if (csdev) /* use device name if csdev found */ + assoc_name = dev_name(&csdev->dev); + else /* otherwise node name for later association */ + assoc_name = cs_np->full_name; + of_node_put(cs_np); + } + } + /* set up a connection */ + err = cti_add_connection_entry(dev, drvdata, tc, csdev, assoc_name); + +of_create_con_err: + return err; +} + +static int of_cti_create_impdef_connections(struct device *dev, + struct cti_drvdata *drvdata, + struct device_node *np) +{ + int rc = 0; + struct device_node *nc = NULL; + + for_each_child_of_node(np, nc) { + if (of_node_cmp(nc->name, CTI_DT_CONNS) != 0) + continue; + rc = of_cti_create_connection(dev, drvdata, nc); + if (rc != 0) + break; + } + return rc; +} + /* get the hardware configuration & connection data. */ int of_cti_get_hw_data(struct device *dev, struct device_node *np, @@ -164,12 +356,19 @@ int of_cti_get_hw_data(struct device *dev, int rc = 0; struct cti_device *cti_dev = &drvdata->ctidev;
- /* check for a v8 architectural CTI device */ - if (of_property_read_bool(np, CTI_DT_V8ARCH)) { + /* get any CTM ID - defaults to 0 */ + of_property_read_u32(np, CTI_DT_CTM_ID, &cti_dev->ctm_id); + + /* + * Check for a v8 architectural CTI device, + * otherwise implementation defined. + */ + if (of_property_read_bool(np, CTI_DT_V8ARCH)) rc = of_cti_create_v8_connections(dev, drvdata, np); - if (rc) - return rc; - } + else + rc = of_cti_create_impdef_connections(dev, drvdata, np); + if (rc) + return rc;
/* if no connections, just add a single default based on max IN-OUT */ if (cti_dev->nr_trig_con == 0)
On Mon, Aug 19, 2019 at 10:13:53PM +0100, Mike Leach wrote:
Adds support for CTIs whose connections are implementation defined at hardware design time, and not constrained by v8 architecture.
These CTIs have no standard connection setup, all the settings have to be defined in the device tree files. The patch creates a set of connections and trigger signals based on the information provided.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../coresight/coresight-cti-platform.c | 209 +++++++++++++++++- 1 file changed, 204 insertions(+), 5 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c index 3ee5b8f8d245..b7649f75f08b 100644 --- a/drivers/hwtracing/coresight/coresight-cti-platform.c +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -13,9 +13,19 @@ #define NR_V8PE_OUT_SIGS 3 #define NR_V8ETM_INOUT_SIGS 4 +/* CTI device tree trigger connection node keyword */ +#define CTI_DT_CONNS "trig-conns"
/* CTI device tree connection property keywords */ #define CTI_DT_V8ARCH "arm,cti-v8-arch" #define CTI_DT_CSDEV_ASSOC "arm,cs-dev-assoc" +#define CTI_DT_CTM_ID "arm,cti-ctm-id" +#define CTI_DT_TRIGIN_SIGS "arm,trig-in-sigs" +#define CTI_DT_TRIGOUT_SIGS "arm,trig-out-sigs" +#define CTI_DT_TRIGIN_TYPES "arm,trig-in-types" +#define CTI_DT_TRIGOUT_TYPES "arm,trig-out-types" +#define CTI_DT_FILTER_OUT_SIGS "arm,trig-filters" +#define CTI_DT_CONN_NAME "arm,trig-conn-name" /*
- Find a registered coresight device from a device fwnode.
@@ -156,6 +166,188 @@ static int of_cti_create_v8_connections(struct device *dev, return ret; }
+static int of_count_sig_elements(const struct device_node *np,
const char *name)
+{
- int nr_elem = of_property_count_elems_of_size(np, name, 4);
- return (nr_elem < 0 ? 0 : nr_elem);
+}
+static int of_cti_read_trig_group(struct cti_trig_grp *tgrp,
struct device_node *np,
const char *grp_name)
+{
- int items = tgrp->nr_sigs, err = 0;
- u32 value, pidx;
- if (!items)
return 0;
- /* set the signal usage mask */
- for (pidx = 0; pidx < items; pidx++) {
err = of_property_read_u32_index(np, grp_name, pidx, &value);
if (err)
return err;
tgrp->used_mask |= BIT(value);
- }
- return 0;
+}
+static int of_cti_read_trig_types(struct cti_trig_grp *tgrp,
struct device_node *np,
const char *type_name)
+{
- int items, used = 0, err = 0, nr_sigs;
- u32 value, i;
- /* allocate an array according to number of signals in connection */
- nr_sigs = tgrp->nr_sigs;
- if (!nr_sigs)
return 0;
- /* see if any types have been included in the device description */
- items = of_count_sig_elements(np, type_name);
- if (items > nr_sigs)
return -EINVAL;
- /*
* Match type id to signal index, 1st type to 1st index etc.
* If fewer types than signals default remainer to GEN_IO.
*/
- for (i = 0; i < nr_sigs; i++) {
if (used < items) {
err = of_property_read_u32_index(np, type_name,
i, &value);
if (!err)
tgrp->sig_types[i] = value;
Should we check that 'value' falls within what we expect? That would mean adding a MAX element to the defines in coresight-cti-dt.h. Another acceptable way would be to add a comment to say where this is checked when the configuration is being applied.
else
tgrp->sig_types[i] = GEN_IO;
used++;
} else
tgrp->sig_types[i] = GEN_IO;
Even if checkpatch doesn't complain you need curly braces around the else condition.
- }
- return 0;
+}
+static int of_cti_process_filter_sigs(struct cti_drvdata *drvdata,
struct device_node *np)
+{
- struct cti_trig_grp *tg = NULL;
- int err = 0, nr_filter_sigs;
- nr_filter_sigs = of_count_sig_elements(np, CTI_DT_FILTER_OUT_SIGS);
- if (nr_filter_sigs == 0)
return 0;
- if (nr_filter_sigs > drvdata->config.nr_trig_max)
return -EINVAL;
- tg = kzalloc(sizeof(*tg), GFP_KERNEL);
- if (!tg)
return -ENOMEM;
- err = of_cti_read_trig_group(tg, np, CTI_DT_FILTER_OUT_SIGS);
- if (!err)
drvdata->config.trig_out_filter |= tg->used_mask;
- kfree(tg);
- return err;
+}
+static int of_cti_create_connection(struct device *dev,
struct cti_drvdata *drvdata,
struct device_node *np)
+{
- struct cti_trig_con *tc = NULL;
- int cpuid = -1, err = 0;
- struct device_node *cs_np = NULL;
- struct coresight_device *csdev = NULL;
- const char *assoc_name = "unknown";
- char cpu_name_str[16];
- struct fwnode_handle *r_fwnode;
- int nr_sigs_in, nr_sigs_out;
- /* look to see how many in and out signals we have */
- nr_sigs_in = of_count_sig_elements(np, CTI_DT_TRIGIN_SIGS);
- nr_sigs_out = of_count_sig_elements(np, CTI_DT_TRIGOUT_SIGS);
- if ((nr_sigs_in > drvdata->config.nr_trig_max) ||
(nr_sigs_out > drvdata->config.nr_trig_max))
return -EINVAL;
- tc = cti_allocate_trig_con(dev, nr_sigs_in, nr_sigs_out);
- if (!tc)
return -ENOMEM;
- /* look for the signals properties. */
- err = of_cti_read_trig_group(tc->con_in, np, CTI_DT_TRIGIN_SIGS);
- if (err)
goto of_create_con_err;
- err = of_cti_read_trig_types(tc->con_in, np, CTI_DT_TRIGIN_TYPES);
- if (err)
goto of_create_con_err;
- err = of_cti_read_trig_group(tc->con_out, np, CTI_DT_TRIGOUT_SIGS);
- if (err)
goto of_create_con_err;
- err = of_cti_read_trig_types(tc->con_out, np, CTI_DT_TRIGOUT_TYPES);
- if (err)
goto of_create_con_err;
- err = of_cti_process_filter_sigs(drvdata, np);
- if (err)
goto of_create_con_err;
- /* read the connection name if set - may be overridden by later */
- of_property_read_string(np, CTI_DT_CONN_NAME, &assoc_name);
- /* associated cpu ? */
- cpuid = of_cti_get_cpu_at_node(np);
- if (cpuid >= 0) {
drvdata->ctidev.cpu = cpuid;
scnprintf(cpu_name_str, sizeof(cpu_name_str), "cpu%d", cpuid);
assoc_name = cpu_name_str;
- } else {
/* associated device ? */
cs_np = of_parse_phandle(np, CTI_DT_CSDEV_ASSOC, 0);
if (cs_np) {
r_fwnode = of_fwnode_handle(cs_np);
csdev = cti_get_assoc_csdev_by_fwnode(r_fwnode);
if (csdev) /* use device name if csdev found */
assoc_name = dev_name(&csdev->dev);
else /* otherwise node name for later association */
assoc_name = cs_np->full_name;
of_node_put(cs_np);
}
- }
- /* set up a connection */
- err = cti_add_connection_entry(dev, drvdata, tc, csdev, assoc_name);
+of_create_con_err:
- return err;
+}
+static int of_cti_create_impdef_connections(struct device *dev,
struct cti_drvdata *drvdata,
struct device_node *np)
+{
- int rc = 0;
- struct device_node *nc = NULL;
- for_each_child_of_node(np, nc) {
if (of_node_cmp(nc->name, CTI_DT_CONNS) != 0)
continue;
rc = of_cti_create_connection(dev, drvdata, nc);
if (rc != 0)
break;
- }
- return rc;
+}
/* get the hardware configuration & connection data. */ int of_cti_get_hw_data(struct device *dev, struct device_node *np, @@ -164,12 +356,19 @@ int of_cti_get_hw_data(struct device *dev, int rc = 0; struct cti_device *cti_dev = &drvdata->ctidev;
- /* check for a v8 architectural CTI device */
- if (of_property_read_bool(np, CTI_DT_V8ARCH)) {
- /* get any CTM ID - defaults to 0 */
- of_property_read_u32(np, CTI_DT_CTM_ID, &cti_dev->ctm_id);
cti_dev->ctm_id isn't used in this patch - it should be introduced later when there is a need for it.
- /*
* Check for a v8 architectural CTI device,
* otherwise implementation defined.
*/
- if (of_property_read_bool(np, CTI_DT_V8ARCH)) rc = of_cti_create_v8_connections(dev, drvdata, np);
if (rc)
return rc;
- }
- else
rc = of_cti_create_impdef_connections(dev, drvdata, np);
If you followed my advice about moving of_cti_create_v8_connections() to cti_create_v8_connections() then this should be cti_create_impdef_connections() and the is_of_node() check done in there.
- if (rc)
return rc;
/* if no connections, just add a single default based on max IN-OUT */ if (cti_dev->nr_trig_con == 0) -- 2.17.1
The CoreSight subsystem enables a path of devices from source to sink. Any CTI devices associated with the path devices must be enabled at the same time.
This patch adds an associated coresight_device element to the main coresight device structure, and uses this to create associations between the CTI and other devices based on the device tree data. The associated device element is used to enable CTI in conjunction with the path elements.
CTI devices are reference counted so where a single CTI is associated with multiple elements on the path, it will be enabled on the first associated device enable, and disabled with the last associated device disable.
Signed-off-by: Mike Leach mike.leach@linaro.org --- .../coresight/coresight-cti-platform.c | 2 + drivers/hwtracing/coresight/coresight-cti.c | 87 +++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.h | 1 + .../hwtracing/coresight/coresight-platform.c | 23 +++++ drivers/hwtracing/coresight/coresight-priv.h | 7 ++ drivers/hwtracing/coresight/coresight.c | 56 ++++++++++-- include/linux/coresight.h | 5 ++ 7 files changed, 176 insertions(+), 5 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c index b7649f75f08b..c57ecbfd792d 100644 --- a/drivers/hwtracing/coresight/coresight-cti-platform.c +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -393,6 +393,7 @@ int of_get_coresight_cti_platform_data(struct device *dev,
return ret; } + #else inline int of_get_coresight_cti_platform_data(struct device *dev, @@ -427,3 +428,4 @@ coresight_cti_get_platform_data(struct device *dev) error: return ERR_PTR(ret); } + diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 9b0441d8be61..927f58af92a2 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -450,6 +450,90 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, return err; }
+/* + * Look for a matching connection device name in the list of + * connections. If found then swap in the csdev name and return + * found. + */ +static bool +cti_match_con_name(struct cti_device *ctidev, const char *node_name, + const char *csdev_name) +{ + struct cti_trig_con *trig_con; + + list_for_each_entry(trig_con, &ctidev->trig_cons, node) { + if (trig_con->con_dev_name) { + if (!strcmp(node_name, trig_con->con_dev_name)) { + /* match: so swap in csdev name */ + kfree(trig_con->con_dev_name); + trig_con->con_dev_name = + kstrdup(csdev_name, GFP_KERNEL); + return true; + } + } + } + return false; +} + +/* + * Search the cti list to add an associated CTI into the supplied CS device + * This will set the association if CTI declared before the CS device + */ +void cti_add_assoc_to_csdev(struct coresight_device *csdev) +{ + struct cti_drvdata *ect_item; + struct cti_device *ctidev; + const char *node_name = NULL, *csdev_name; + + /* protect the list */ + mutex_lock(&ect_mutex); + + /* exit if current is an ECT device.*/ + if ((csdev->type == CORESIGHT_DEV_TYPE_ECT) || list_empty(&ect_net)) + goto cti_add_done; + + /* if we didn't find the csdev previously we used the fwnode name */ + node_name = coresight_get_fwnode_name(csdev->dev.parent); + + if (!node_name) + goto cti_add_done; + + /* this is the name we want to use for the association */ + csdev_name = dev_name(&csdev->dev); + + /* for each CTI in list... */ + list_for_each_entry(ect_item, &ect_net, node) { + ctidev = &ect_item->ctidev; + if (cti_match_con_name(ctidev, node_name, csdev_name)) { + /* + * if we found a matching name then update the + * association pointers. + */ + csdev->ect_dev = ect_item->csdev; + goto cti_add_done; + } + } +cti_add_done: + mutex_unlock(&ect_mutex); +} +EXPORT_SYMBOL_GPL(cti_add_assoc_to_csdev); + +/* + * Update the cross references where the associated device was found + * while we were building the connection info. This will occur if the + * assoc device was registered before the CTI. + */ +static void cti_update_conn_xrefs(struct cti_drvdata *drvdata) +{ + struct cti_trig_con *tc; + struct cti_device *ctidev = &drvdata->ctidev; + + list_for_each_entry(tc, &ctidev->trig_cons, node) { + if (tc->con_dev) + tc->con_dev->ect_dev = drvdata->csdev; + } +} + /** cti ect operations **/ int cti_enable(struct coresight_device *csdev) { @@ -585,6 +669,9 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) drvdata->csdev_release = drvdata->csdev->dev.release; drvdata->csdev->dev.release = cti_device_release;
+ /* set any cross references */ + cti_update_conn_xrefs(drvdata); + /* all done - dec pm refcount */ pm_runtime_put(&adev->dev); dev_info(dev, "%s: CTI initialized\n", cti_desc.name); diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index 865d3d0ffb11..90622f3be12b 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -224,6 +224,7 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, u32 channel_idx); struct coresight_platform_data * coresight_cti_get_platform_data(struct device *dev); +const char *coresight_cti_get_node_name(struct device *dev);
/* cti powered and enabled */ #define CTI_PWR_ENA(p_cfg) (p_cfg->hw_enabled && p_cfg->hw_powered) diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c index 3c5bee429105..6721cb1af5fe 100644 --- a/drivers/hwtracing/coresight/coresight-platform.c +++ b/drivers/hwtracing/coresight/coresight-platform.c @@ -293,6 +293,12 @@ static int of_get_coresight_platform_data(struct device *dev,
return 0; } + +static inline const char *of_coresight_get_node_name(struct device *dev) +{ + return dev->of_node->full_name; +} + #else static inline int of_get_coresight_platform_data(struct device *dev, @@ -305,6 +311,11 @@ static inline int of_coresight_get_cpu(struct device *dev) { return -ENODEV; } + +static inline const char *of_coresight_get_node_name(struct device *dev) +{ + return NULL; +} #endif
#ifdef CONFIG_ACPI @@ -766,6 +777,18 @@ static inline int acpi_coresight_get_cpu(struct device *dev) } #endif
+const char *coresight_get_fwnode_name(struct device *dev) +{ + const char *node_name = NULL; + struct fwnode_handle *fwnode = dev_fwnode(dev); + + if (is_of_node(fwnode)) + node_name = of_coresight_get_node_name(dev); + + return node_name; +} +EXPORT_SYMBOL_GPL(coresight_get_fwnode_name); + int coresight_get_cpu(struct device *dev) { if (is_of_node(dev->fwnode)) diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index aba6b789c969..4c176498a367 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -162,6 +162,13 @@ static inline int etm_readl_cp14(u32 off, unsigned int *val) { return 0; } static inline int etm_writel_cp14(u32 off, u32 val) { return 0; } #endif
+#ifdef CONFIG_CORESIGHT_CTI +extern void cti_add_assoc_to_csdev(struct coresight_device *csdev); +#else +static inline int cti_add_assoc_to_csdev(struct coresight_device *csdev) +{ return 0; } +#endif + /* * Macros and inline functions to handle CoreSight UCI data and driver * private data in AMBA ID table entries, and extract data values. diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 64ff810394f9..52b294dd898e 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -216,6 +216,31 @@ void coresight_disclaim_device(void __iomem *base) CS_LOCK(base); }
+/* enable or disable an associated CTI device of the supplied CS device */ +static int +coresight_control_assoc_ectdev(struct coresight_device *csdev, bool enable) +{ + int ect_ret = 0; + struct coresight_device *ect_csdev = csdev->ect_dev; + + if (!ect_csdev) + return 0; + + if (enable) { + if (ect_ops(ect_csdev)->enable) + ect_ret = ect_ops(ect_csdev)->enable(ect_csdev); + } else { + if (ect_ops(ect_csdev)->disable) + ect_ret = ect_ops(ect_csdev)->disable(ect_csdev); + } + + /* output warning if ECT enable is preventing trace operation */ + if (ect_ret) + dev_info(&csdev->dev, "Associated ECT device (%s) %s failed\n", + dev_name(&ect_csdev->dev), enable ? "enable" : "disable"); + return ect_ret; +} + static int coresight_enable_sink(struct coresight_device *csdev, u32 mode, void *data) { @@ -228,11 +253,15 @@ static int coresight_enable_sink(struct coresight_device *csdev, if (!sink_ops(csdev)->enable) return -EINVAL;
- ret = sink_ops(csdev)->enable(csdev, mode, data); + ret = coresight_control_assoc_ectdev(csdev, true); if (ret) return ret; + ret = sink_ops(csdev)->enable(csdev, mode, data); + if (ret) { + coresight_control_assoc_ectdev(csdev, false); + return ret; + } csdev->enable = true; - return 0; }
@@ -246,6 +275,7 @@ static void coresight_disable_sink(struct coresight_device *csdev) ret = sink_ops(csdev)->disable(csdev); if (ret) return; + coresight_control_assoc_ectdev(csdev, false); csdev->enable = false; }
@@ -276,7 +306,14 @@ static int coresight_enable_link(struct coresight_device *csdev,
if (atomic_inc_return(&csdev->refcnt[refport]) == 1) { if (link_ops(csdev)->enable) { - ret = link_ops(csdev)->enable(csdev, inport, outport); + ret = coresight_control_assoc_ectdev(csdev, true); + if (!ret) { + ret = link_ops(csdev)->enable(csdev, inport, + outport); + if (ret) + coresight_control_assoc_ectdev(csdev, + false); + } if (ret) { atomic_dec(&csdev->refcnt[refport]); return ret; @@ -316,8 +353,10 @@ static void coresight_disable_link(struct coresight_device *csdev, }
if (atomic_dec_return(&csdev->refcnt[refport]) == 0) { - if (link_ops(csdev)->disable) + if (link_ops(csdev)->disable) { link_ops(csdev)->disable(csdev, inport, outport); + coresight_control_assoc_ectdev(csdev, false); + } }
for (i = 0; i < nr_conns; i++) @@ -339,9 +378,14 @@ static int coresight_enable_source(struct coresight_device *csdev, u32 mode)
if (!csdev->enable) { if (source_ops(csdev)->enable) { - ret = source_ops(csdev)->enable(csdev, NULL, mode); + ret = coresight_control_assoc_ectdev(csdev, true); if (ret) return ret; + ret = source_ops(csdev)->enable(csdev, NULL, mode); + if (ret) { + coresight_control_assoc_ectdev(csdev, false); + return ret; + }; } csdev->enable = true; } @@ -364,6 +408,7 @@ static bool coresight_disable_source(struct coresight_device *csdev) if (atomic_dec_return(csdev->refcnt) == 0) { if (source_ops(csdev)->disable) source_ops(csdev)->disable(csdev, NULL); + coresight_control_assoc_ectdev(csdev, false); csdev->enable = false; } return !csdev->enable; @@ -1270,6 +1315,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
coresight_fixup_device_conns(csdev); coresight_fixup_orphan_conns(csdev); + cti_add_assoc_to_csdev(csdev);
mutex_unlock(&coresight_mutex);
diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 2a23c3cdf8e4..ff97e9a7080a 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -163,6 +163,8 @@ struct coresight_connection { * activated but not yet enabled. Enabling for a _sink_ * appens when a source has been selected for that it. * @ea: Device attribute for sink representation under PMU directory. + * @ect_dev: Associated cross trigger device. Not part of the trace data + * path or connections. */ struct coresight_device { struct coresight_platform_data *pdata; @@ -176,6 +178,8 @@ struct coresight_device { /* sink specific fields */ bool activated; /* true only if a sink is part of a path */ struct dev_ext_attribute *ea; + /* cross trigger handling */ + struct coresight_device *ect_dev; };
/* @@ -335,5 +339,6 @@ static inline void coresight_disclaim_device_unlocked(void __iomem *base) {} extern int coresight_get_cpu(struct device *dev);
struct coresight_platform_data *coresight_get_platform_data(struct device *dev); +extern const char *coresight_get_fwnode_name(struct device *dev);
#endif
On Mon, Aug 19, 2019 at 10:13:54PM +0100, Mike Leach wrote:
The CoreSight subsystem enables a path of devices from source to sink. Any CTI devices associated with the path devices must be enabled at the same time.
This patch adds an associated coresight_device element to the main coresight device structure, and uses this to create associations between the CTI and other devices based on the device tree data. The associated device element is used to enable CTI in conjunction with the path elements.
CTI devices are reference counted so where a single CTI is associated with multiple elements on the path, it will be enabled on the first associated device enable, and disabled with the last associated device disable.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../coresight/coresight-cti-platform.c | 2 + drivers/hwtracing/coresight/coresight-cti.c | 87 +++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.h | 1 + .../hwtracing/coresight/coresight-platform.c | 23 +++++ drivers/hwtracing/coresight/coresight-priv.h | 7 ++ drivers/hwtracing/coresight/coresight.c | 56 ++++++++++-- include/linux/coresight.h | 5 ++ 7 files changed, 176 insertions(+), 5 deletions(-)
I got the following when applying this patch:
mpoirier@xps15:~/work/coresight/kernel-maint$ git am /0008-coresight-cti-Enable-CTI-associated-with-devices.patch Applying: coresight: cti: Enable CTI associated with devices. .git/rebase-apply/patch:27: new blank line at EOF. + warning: 1 line adds whitespace errors.
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c index b7649f75f08b..c57ecbfd792d 100644 --- a/drivers/hwtracing/coresight/coresight-cti-platform.c +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -393,6 +393,7 @@ int of_get_coresight_cti_platform_data(struct device *dev, return ret; }
Spurious newline, please remove.
#else inline int of_get_coresight_cti_platform_data(struct device *dev, @@ -427,3 +428,4 @@ coresight_cti_get_platform_data(struct device *dev) error: return ERR_PTR(ret); }
Same
diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 9b0441d8be61..927f58af92a2 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -450,6 +450,90 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, return err; } +/*
- Look for a matching connection device name in the list of
- connections. If found then swap in the csdev name and return
- found.
- */
+static bool +cti_match_con_name(struct cti_device *ctidev, const char *node_name,
const char *csdev_name)
+{
- struct cti_trig_con *trig_con;
- list_for_each_entry(trig_con, &ctidev->trig_cons, node) {
if (trig_con->con_dev_name) {
if (!strcmp(node_name, trig_con->con_dev_name)) {
/* match: so swap in csdev name */
kfree(trig_con->con_dev_name);
trig_con->con_dev_name =
kstrdup(csdev_name, GFP_KERNEL);
return true;
}
}
- }
- return false;
+}
+/*
- Search the cti list to add an associated CTI into the supplied CS device
- This will set the association if CTI declared before the CS device
- */
+void cti_add_assoc_to_csdev(struct coresight_device *csdev) +{
- struct cti_drvdata *ect_item;
- struct cti_device *ctidev;
- const char *node_name = NULL, *csdev_name;
- /* protect the list */
- mutex_lock(&ect_mutex);
- /* exit if current is an ECT device.*/
- if ((csdev->type == CORESIGHT_DEV_TYPE_ECT) || list_empty(&ect_net))
goto cti_add_done;
- /* if we didn't find the csdev previously we used the fwnode name */
- node_name = coresight_get_fwnode_name(csdev->dev.parent);
- if (!node_name)
goto cti_add_done;
- /* this is the name we want to use for the association */
- csdev_name = dev_name(&csdev->dev);
- /* for each CTI in list... */
- list_for_each_entry(ect_item, &ect_net, node) {
ctidev = &ect_item->ctidev;
if (cti_match_con_name(ctidev, node_name, csdev_name)) {
/*
* if we found a matching name then update the
* association pointers.
*/
csdev->ect_dev = ect_item->csdev;
goto cti_add_done;
}
- }
+cti_add_done:
- mutex_unlock(&ect_mutex);
+} +EXPORT_SYMBOL_GPL(cti_add_assoc_to_csdev);
+/*
- Update the cross references where the associated device was found
- while we were building the connection info. This will occur if the
- assoc device was registered before the CTI.
- */
+static void cti_update_conn_xrefs(struct cti_drvdata *drvdata) +{
- struct cti_trig_con *tc;
- struct cti_device *ctidev = &drvdata->ctidev;
- list_for_each_entry(tc, &ctidev->trig_cons, node) {
if (tc->con_dev)
tc->con_dev->ect_dev = drvdata->csdev;
- }
+}
/** cti ect operations **/ int cti_enable(struct coresight_device *csdev) { @@ -585,6 +669,9 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) drvdata->csdev_release = drvdata->csdev->dev.release; drvdata->csdev->dev.release = cti_device_release;
- /* set any cross references */
- cti_update_conn_xrefs(drvdata);
- /* all done - dec pm refcount */ pm_runtime_put(&adev->dev); dev_info(dev, "%s: CTI initialized\n", cti_desc.name);
diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index 865d3d0ffb11..90622f3be12b 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -224,6 +224,7 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, u32 channel_idx); struct coresight_platform_data * coresight_cti_get_platform_data(struct device *dev); +const char *coresight_cti_get_node_name(struct device *dev);
I can't find where this is defined or used - please remove.
/* cti powered and enabled */ #define CTI_PWR_ENA(p_cfg) (p_cfg->hw_enabled && p_cfg->hw_powered) diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c index 3c5bee429105..6721cb1af5fe 100644 --- a/drivers/hwtracing/coresight/coresight-platform.c +++ b/drivers/hwtracing/coresight/coresight-platform.c @@ -293,6 +293,12 @@ static int of_get_coresight_platform_data(struct device *dev, return 0; }
+static inline const char *of_coresight_get_node_name(struct device *dev) +{
- return dev->of_node->full_name;
+}
#else static inline int of_get_coresight_platform_data(struct device *dev, @@ -305,6 +311,11 @@ static inline int of_coresight_get_cpu(struct device *dev) { return -ENODEV; }
+static inline const char *of_coresight_get_node_name(struct device *dev) +{
- return NULL;
+} #endif #ifdef CONFIG_ACPI @@ -766,6 +777,18 @@ static inline int acpi_coresight_get_cpu(struct device *dev) } #endif +const char *coresight_get_fwnode_name(struct device *dev) +{
- const char *node_name = NULL;
- struct fwnode_handle *fwnode = dev_fwnode(dev);
- if (is_of_node(fwnode))
node_name = of_coresight_get_node_name(dev);
- return node_name;
+} +EXPORT_SYMBOL_GPL(coresight_get_fwnode_name);
int coresight_get_cpu(struct device *dev) { if (is_of_node(dev->fwnode)) diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index aba6b789c969..4c176498a367 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -162,6 +162,13 @@ static inline int etm_readl_cp14(u32 off, unsigned int *val) { return 0; } static inline int etm_writel_cp14(u32 off, u32 val) { return 0; } #endif +#ifdef CONFIG_CORESIGHT_CTI +extern void cti_add_assoc_to_csdev(struct coresight_device *csdev); +#else +static inline int cti_add_assoc_to_csdev(struct coresight_device *csdev) +{ return 0; }
static inline void cti_add_assoc_to_csdev(struct coresight_device *csdev) {}
+#endif
/*
- Macros and inline functions to handle CoreSight UCI data and driver
- private data in AMBA ID table entries, and extract data values.
diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 64ff810394f9..52b294dd898e 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -216,6 +216,31 @@ void coresight_disclaim_device(void __iomem *base) CS_LOCK(base); } +/* enable or disable an associated CTI device of the supplied CS device */ +static int +coresight_control_assoc_ectdev(struct coresight_device *csdev, bool enable) +{
- int ect_ret = 0;
- struct coresight_device *ect_csdev = csdev->ect_dev;
- if (!ect_csdev)
return 0;
- if (enable) {
if (ect_ops(ect_csdev)->enable)
ect_ret = ect_ops(ect_csdev)->enable(ect_csdev);
- } else {
if (ect_ops(ect_csdev)->disable)
ect_ret = ect_ops(ect_csdev)->disable(ect_csdev);
- }
- /* output warning if ECT enable is preventing trace operation */
- if (ect_ret)
dev_info(&csdev->dev, "Associated ECT device (%s) %s failed\n",
dev_name(&ect_csdev->dev), enable ? "enable" : "disable");
- return ect_ret;
+}
static int coresight_enable_sink(struct coresight_device *csdev, u32 mode, void *data) { @@ -228,11 +253,15 @@ static int coresight_enable_sink(struct coresight_device *csdev, if (!sink_ops(csdev)->enable) return -EINVAL;
- ret = sink_ops(csdev)->enable(csdev, mode, data);
- ret = coresight_control_assoc_ectdev(csdev, true); if (ret) return ret;
- ret = sink_ops(csdev)->enable(csdev, mode, data);
- if (ret) {
coresight_control_assoc_ectdev(csdev, false);
return ret;
- } csdev->enable = true;
- return 0;
} @@ -246,6 +275,7 @@ static void coresight_disable_sink(struct coresight_device *csdev) ret = sink_ops(csdev)->disable(csdev); if (ret) return;
- coresight_control_assoc_ectdev(csdev, false); csdev->enable = false;
} @@ -276,7 +306,14 @@ static int coresight_enable_link(struct coresight_device *csdev, if (atomic_inc_return(&csdev->refcnt[refport]) == 1) { if (link_ops(csdev)->enable) {
ret = link_ops(csdev)->enable(csdev, inport, outport);
ret = coresight_control_assoc_ectdev(csdev, true);
if (!ret) {
ret = link_ops(csdev)->enable(csdev, inport,
outport);
if (ret)
coresight_control_assoc_ectdev(csdev,
false);
} if (ret) { atomic_dec(&csdev->refcnt[refport]); return ret;
@@ -316,8 +353,10 @@ static void coresight_disable_link(struct coresight_device *csdev, } if (atomic_dec_return(&csdev->refcnt[refport]) == 0) {
if (link_ops(csdev)->disable)
if (link_ops(csdev)->disable) { link_ops(csdev)->disable(csdev, inport, outport);
coresight_control_assoc_ectdev(csdev, false);
}}
for (i = 0; i < nr_conns; i++) @@ -339,9 +378,14 @@ static int coresight_enable_source(struct coresight_device *csdev, u32 mode) if (!csdev->enable) { if (source_ops(csdev)->enable) {
ret = source_ops(csdev)->enable(csdev, NULL, mode);
ret = coresight_control_assoc_ectdev(csdev, true); if (ret) return ret;
ret = source_ops(csdev)->enable(csdev, NULL, mode);
if (ret) {
coresight_control_assoc_ectdev(csdev, false);
return ret;
} csdev->enable = true; }};
@@ -364,6 +408,7 @@ static bool coresight_disable_source(struct coresight_device *csdev) if (atomic_dec_return(csdev->refcnt) == 0) { if (source_ops(csdev)->disable) source_ops(csdev)->disable(csdev, NULL);
csdev->enable = false; } return !csdev->enable;coresight_control_assoc_ectdev(csdev, false);
@@ -1270,6 +1315,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc) coresight_fixup_device_conns(csdev); coresight_fixup_orphan_conns(csdev);
- cti_add_assoc_to_csdev(csdev);
mutex_unlock(&coresight_mutex); diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 2a23c3cdf8e4..ff97e9a7080a 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -163,6 +163,8 @@ struct coresight_connection {
activated but not yet enabled. Enabling for a _sink_
appens when a source has been selected for that it.
- @ea: Device attribute for sink representation under PMU directory.
- @ect_dev: Associated cross trigger device. Not part of the trace data
*/
path or connections.
struct coresight_device { struct coresight_platform_data *pdata; @@ -176,6 +178,8 @@ struct coresight_device { /* sink specific fields */ bool activated; /* true only if a sink is part of a path */ struct dev_ext_attribute *ea;
- /* cross trigger handling */
- struct coresight_device *ect_dev;
}; /* @@ -335,5 +339,6 @@ static inline void coresight_disclaim_device_unlocked(void __iomem *base) {} extern int coresight_get_cpu(struct device *dev); struct coresight_platform_data *coresight_get_platform_data(struct device *dev); +extern const char *coresight_get_fwnode_name(struct device *dev);
#endif
2.17.1
On Mon, Aug 19, 2019 at 10:13:54PM +0100, Mike Leach wrote:
The CoreSight subsystem enables a path of devices from source to sink. Any CTI devices associated with the path devices must be enabled at the same time.
This patch adds an associated coresight_device element to the main coresight device structure, and uses this to create associations between the CTI and other devices based on the device tree data. The associated device element is used to enable CTI in conjunction with the path elements.
CTI devices are reference counted so where a single CTI is associated with multiple elements on the path, it will be enabled on the first associated device enable, and disabled with the last associated device disable.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../coresight/coresight-cti-platform.c | 2 + drivers/hwtracing/coresight/coresight-cti.c | 87 +++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.h | 1 + .../hwtracing/coresight/coresight-platform.c | 23 +++++ drivers/hwtracing/coresight/coresight-priv.h | 7 ++ drivers/hwtracing/coresight/coresight.c | 56 ++++++++++-- include/linux/coresight.h | 5 ++ 7 files changed, 176 insertions(+), 5 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c index b7649f75f08b..c57ecbfd792d 100644 --- a/drivers/hwtracing/coresight/coresight-cti-platform.c +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -393,6 +393,7 @@ int of_get_coresight_cti_platform_data(struct device *dev, return ret; }
#else inline int of_get_coresight_cti_platform_data(struct device *dev, @@ -427,3 +428,4 @@ coresight_cti_get_platform_data(struct device *dev) error: return ERR_PTR(ret); }
diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 9b0441d8be61..927f58af92a2 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -450,6 +450,90 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, return err; } +/*
- Look for a matching connection device name in the list of
- connections. If found then swap in the csdev name and return
- found.
- */
+static bool +cti_match_con_name(struct cti_device *ctidev, const char *node_name,
const char *csdev_name)
+{
- struct cti_trig_con *trig_con;
- list_for_each_entry(trig_con, &ctidev->trig_cons, node) {
if (trig_con->con_dev_name) {
if (!strcmp(node_name, trig_con->con_dev_name)) {
/* match: so swap in csdev name */
kfree(trig_con->con_dev_name);
trig_con->con_dev_name =
kstrdup(csdev_name, GFP_KERNEL);
return true;
}
}
- }
- return false;
+}
+/*
- Search the cti list to add an associated CTI into the supplied CS device
- This will set the association if CTI declared before the CS device
- */
+void cti_add_assoc_to_csdev(struct coresight_device *csdev) +{
- struct cti_drvdata *ect_item;
- struct cti_device *ctidev;
- const char *node_name = NULL, *csdev_name;
- /* protect the list */
- mutex_lock(&ect_mutex);
There is no need to grab the mutex that early on. Please move to just before searching the list.
- /* exit if current is an ECT device.*/
- if ((csdev->type == CORESIGHT_DEV_TYPE_ECT) || list_empty(&ect_net))
goto cti_add_done;
- /* if we didn't find the csdev previously we used the fwnode name */
- node_name = coresight_get_fwnode_name(csdev->dev.parent);
- if (!node_name)
goto cti_add_done;
- /* this is the name we want to use for the association */
- csdev_name = dev_name(&csdev->dev);
- /* for each CTI in list... */
- list_for_each_entry(ect_item, &ect_net, node) {
ctidev = &ect_item->ctidev;
if (cti_match_con_name(ctidev, node_name, csdev_name)) {
/*
* if we found a matching name then update the
* association pointers.
*/
csdev->ect_dev = ect_item->csdev;
goto cti_add_done;
}
- }
+cti_add_done:
- mutex_unlock(&ect_mutex);
+} +EXPORT_SYMBOL_GPL(cti_add_assoc_to_csdev);
+/*
- Update the cross references where the associated device was found
- while we were building the connection info. This will occur if the
- assoc device was registered before the CTI.
- */
+static void cti_update_conn_xrefs(struct cti_drvdata *drvdata) +{
- struct cti_trig_con *tc;
- struct cti_device *ctidev = &drvdata->ctidev;
- list_for_each_entry(tc, &ctidev->trig_cons, node) {
if (tc->con_dev)
tc->con_dev->ect_dev = drvdata->csdev;
- }
+}
/** cti ect operations **/ int cti_enable(struct coresight_device *csdev) { @@ -585,6 +669,9 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) drvdata->csdev_release = drvdata->csdev->dev.release; drvdata->csdev->dev.release = cti_device_release;
- /* set any cross references */
- cti_update_conn_xrefs(drvdata);
- /* all done - dec pm refcount */ pm_runtime_put(&adev->dev); dev_info(dev, "%s: CTI initialized\n", cti_desc.name);
diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index 865d3d0ffb11..90622f3be12b 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -224,6 +224,7 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, u32 channel_idx); struct coresight_platform_data * coresight_cti_get_platform_data(struct device *dev); +const char *coresight_cti_get_node_name(struct device *dev); /* cti powered and enabled */ #define CTI_PWR_ENA(p_cfg) (p_cfg->hw_enabled && p_cfg->hw_powered) diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c index 3c5bee429105..6721cb1af5fe 100644 --- a/drivers/hwtracing/coresight/coresight-platform.c +++ b/drivers/hwtracing/coresight/coresight-platform.c @@ -293,6 +293,12 @@ static int of_get_coresight_platform_data(struct device *dev, return 0; }
+static inline const char *of_coresight_get_node_name(struct device *dev) +{
- return dev->of_node->full_name;
+}
#else static inline int of_get_coresight_platform_data(struct device *dev, @@ -305,6 +311,11 @@ static inline int of_coresight_get_cpu(struct device *dev) { return -ENODEV; }
+static inline const char *of_coresight_get_node_name(struct device *dev) +{
- return NULL;
+} #endif #ifdef CONFIG_ACPI @@ -766,6 +777,18 @@ static inline int acpi_coresight_get_cpu(struct device *dev) } #endif +const char *coresight_get_fwnode_name(struct device *dev) +{
- const char *node_name = NULL;
- struct fwnode_handle *fwnode = dev_fwnode(dev);
- if (is_of_node(fwnode))
node_name = of_coresight_get_node_name(dev);
- return node_name;
+} +EXPORT_SYMBOL_GPL(coresight_get_fwnode_name);
int coresight_get_cpu(struct device *dev) { if (is_of_node(dev->fwnode)) diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index aba6b789c969..4c176498a367 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -162,6 +162,13 @@ static inline int etm_readl_cp14(u32 off, unsigned int *val) { return 0; } static inline int etm_writel_cp14(u32 off, u32 val) { return 0; } #endif +#ifdef CONFIG_CORESIGHT_CTI +extern void cti_add_assoc_to_csdev(struct coresight_device *csdev); +#else +static inline int cti_add_assoc_to_csdev(struct coresight_device *csdev) +{ return 0; } +#endif
/*
- Macros and inline functions to handle CoreSight UCI data and driver
- private data in AMBA ID table entries, and extract data values.
diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 64ff810394f9..52b294dd898e 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -216,6 +216,31 @@ void coresight_disclaim_device(void __iomem *base) CS_LOCK(base); } +/* enable or disable an associated CTI device of the supplied CS device */ +static int +coresight_control_assoc_ectdev(struct coresight_device *csdev, bool enable) +{
- int ect_ret = 0;
- struct coresight_device *ect_csdev = csdev->ect_dev;
- if (!ect_csdev)
return 0;
- if (enable) {
if (ect_ops(ect_csdev)->enable)
ect_ret = ect_ops(ect_csdev)->enable(ect_csdev);
- } else {
if (ect_ops(ect_csdev)->disable)
ect_ret = ect_ops(ect_csdev)->disable(ect_csdev);
- }
- /* output warning if ECT enable is preventing trace operation */
- if (ect_ret)
dev_info(&csdev->dev, "Associated ECT device (%s) %s failed\n",
dev_name(&ect_csdev->dev), enable ? "enable" : "disable");
- return ect_ret;
+}
static int coresight_enable_sink(struct coresight_device *csdev, u32 mode, void *data) { @@ -228,11 +253,15 @@ static int coresight_enable_sink(struct coresight_device *csdev, if (!sink_ops(csdev)->enable) return -EINVAL;
- ret = sink_ops(csdev)->enable(csdev, mode, data);
- ret = coresight_control_assoc_ectdev(csdev, true); if (ret) return ret;
- ret = sink_ops(csdev)->enable(csdev, mode, data);
- if (ret) {
coresight_control_assoc_ectdev(csdev, false);
return ret;
- } csdev->enable = true;
- return 0;
} @@ -246,6 +275,7 @@ static void coresight_disable_sink(struct coresight_device *csdev) ret = sink_ops(csdev)->disable(csdev); if (ret) return;
- coresight_control_assoc_ectdev(csdev, false); csdev->enable = false;
} @@ -276,7 +306,14 @@ static int coresight_enable_link(struct coresight_device *csdev, if (atomic_inc_return(&csdev->refcnt[refport]) == 1) { if (link_ops(csdev)->enable) {
ret = link_ops(csdev)->enable(csdev, inport, outport);
ret = coresight_control_assoc_ectdev(csdev, true);
if (!ret) {
ret = link_ops(csdev)->enable(csdev, inport,
outport);
if (ret)
coresight_control_assoc_ectdev(csdev,
false);
} if (ret) { atomic_dec(&csdev->refcnt[refport]); return ret;
@@ -316,8 +353,10 @@ static void coresight_disable_link(struct coresight_device *csdev, } if (atomic_dec_return(&csdev->refcnt[refport]) == 0) {
if (link_ops(csdev)->disable)
if (link_ops(csdev)->disable) { link_ops(csdev)->disable(csdev, inport, outport);
coresight_control_assoc_ectdev(csdev, false);
}}
for (i = 0; i < nr_conns; i++) @@ -339,9 +378,14 @@ static int coresight_enable_source(struct coresight_device *csdev, u32 mode) if (!csdev->enable) { if (source_ops(csdev)->enable) {
ret = source_ops(csdev)->enable(csdev, NULL, mode);
ret = coresight_control_assoc_ectdev(csdev, true); if (ret) return ret;
ret = source_ops(csdev)->enable(csdev, NULL, mode);
if (ret) {
coresight_control_assoc_ectdev(csdev, false);
return ret;
} csdev->enable = true; }};
@@ -364,6 +408,7 @@ static bool coresight_disable_source(struct coresight_device *csdev) if (atomic_dec_return(csdev->refcnt) == 0) { if (source_ops(csdev)->disable) source_ops(csdev)->disable(csdev, NULL);
csdev->enable = false; } return !csdev->enable;coresight_control_assoc_ectdev(csdev, false);
@@ -1270,6 +1315,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc) coresight_fixup_device_conns(csdev); coresight_fixup_orphan_conns(csdev);
- cti_add_assoc_to_csdev(csdev);
mutex_unlock(&coresight_mutex); diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 2a23c3cdf8e4..ff97e9a7080a 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -163,6 +163,8 @@ struct coresight_connection {
activated but not yet enabled. Enabling for a _sink_
appens when a source has been selected for that it.
- @ea: Device attribute for sink representation under PMU directory.
- @ect_dev: Associated cross trigger device. Not part of the trace data
*/
path or connections.
struct coresight_device { struct coresight_platform_data *pdata; @@ -176,6 +178,8 @@ struct coresight_device { /* sink specific fields */ bool activated; /* true only if a sink is part of a path */ struct dev_ext_attribute *ea;
- /* cross trigger handling */
- struct coresight_device *ect_dev;
}; /* @@ -335,5 +339,6 @@ static inline void coresight_disclaim_device_unlocked(void __iomem *base) {} extern int coresight_get_cpu(struct device *dev); struct coresight_platform_data *coresight_get_platform_data(struct device *dev); +extern const char *coresight_get_fwnode_name(struct device *dev);
#endif
2.17.1
Hi Mathieu,
On Thu, 3 Oct 2019 at 18:26, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Mon, Aug 19, 2019 at 10:13:54PM +0100, Mike Leach wrote:
The CoreSight subsystem enables a path of devices from source to sink. Any CTI devices associated with the path devices must be enabled at the same time.
This patch adds an associated coresight_device element to the main coresight device structure, and uses this to create associations between the CTI and other devices based on the device tree data. The associated device element is used to enable CTI in conjunction with the path elements.
CTI devices are reference counted so where a single CTI is associated with multiple elements on the path, it will be enabled on the first associated device enable, and disabled with the last associated device disable.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../coresight/coresight-cti-platform.c | 2 + drivers/hwtracing/coresight/coresight-cti.c | 87 +++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.h | 1 + .../hwtracing/coresight/coresight-platform.c | 23 +++++ drivers/hwtracing/coresight/coresight-priv.h | 7 ++ drivers/hwtracing/coresight/coresight.c | 56 ++++++++++-- include/linux/coresight.h | 5 ++ 7 files changed, 176 insertions(+), 5 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c index b7649f75f08b..c57ecbfd792d 100644 --- a/drivers/hwtracing/coresight/coresight-cti-platform.c +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -393,6 +393,7 @@ int of_get_coresight_cti_platform_data(struct device *dev,
return ret;
}
#else inline int of_get_coresight_cti_platform_data(struct device *dev, @@ -427,3 +428,4 @@ coresight_cti_get_platform_data(struct device *dev) error: return ERR_PTR(ret); }
diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 9b0441d8be61..927f58af92a2 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -450,6 +450,90 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, return err; }
+/*
- Look for a matching connection device name in the list of
- connections. If found then swap in the csdev name and return
- found.
- */
+static bool +cti_match_con_name(struct cti_device *ctidev, const char *node_name,
const char *csdev_name)
+{
struct cti_trig_con *trig_con;
list_for_each_entry(trig_con, &ctidev->trig_cons, node) {
if (trig_con->con_dev_name) {
if (!strcmp(node_name, trig_con->con_dev_name)) {
/* match: so swap in csdev name */
kfree(trig_con->con_dev_name);
trig_con->con_dev_name =
kstrdup(csdev_name, GFP_KERNEL);
return true;
}
}
}
return false;
+}
+/*
- Search the cti list to add an associated CTI into the supplied CS device
- This will set the association if CTI declared before the CS device
- */
+void cti_add_assoc_to_csdev(struct coresight_device *csdev) +{
struct cti_drvdata *ect_item;
struct cti_device *ctidev;
const char *node_name = NULL, *csdev_name;
/* protect the list */
mutex_lock(&ect_mutex);
There is no need to grab the mutex that early on. Please move to just before searching the list.
list_empty() in the ii () below is checking the list - so we do need the mutex here.
Thanks
Mike
/* exit if current is an ECT device.*/
if ((csdev->type == CORESIGHT_DEV_TYPE_ECT) || list_empty(&ect_net))
goto cti_add_done;
/* if we didn't find the csdev previously we used the fwnode name */
node_name = coresight_get_fwnode_name(csdev->dev.parent);
if (!node_name)
goto cti_add_done;
/* this is the name we want to use for the association */
csdev_name = dev_name(&csdev->dev);
/* for each CTI in list... */
list_for_each_entry(ect_item, &ect_net, node) {
ctidev = &ect_item->ctidev;
if (cti_match_con_name(ctidev, node_name, csdev_name)) {
/*
* if we found a matching name then update the
* association pointers.
*/
csdev->ect_dev = ect_item->csdev;
goto cti_add_done;
}
}
+cti_add_done:
mutex_unlock(&ect_mutex);
+} +EXPORT_SYMBOL_GPL(cti_add_assoc_to_csdev);
+/*
- Update the cross references where the associated device was found
- while we were building the connection info. This will occur if the
- assoc device was registered before the CTI.
- */
+static void cti_update_conn_xrefs(struct cti_drvdata *drvdata) +{
struct cti_trig_con *tc;
struct cti_device *ctidev = &drvdata->ctidev;
list_for_each_entry(tc, &ctidev->trig_cons, node) {
if (tc->con_dev)
tc->con_dev->ect_dev = drvdata->csdev;
}
+}
/** cti ect operations **/ int cti_enable(struct coresight_device *csdev) { @@ -585,6 +669,9 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) drvdata->csdev_release = drvdata->csdev->dev.release; drvdata->csdev->dev.release = cti_device_release;
/* set any cross references */
cti_update_conn_xrefs(drvdata);
/* all done - dec pm refcount */ pm_runtime_put(&adev->dev); dev_info(dev, "%s: CTI initialized\n", cti_desc.name);
diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index 865d3d0ffb11..90622f3be12b 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -224,6 +224,7 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, u32 channel_idx); struct coresight_platform_data * coresight_cti_get_platform_data(struct device *dev); +const char *coresight_cti_get_node_name(struct device *dev);
/* cti powered and enabled */ #define CTI_PWR_ENA(p_cfg) (p_cfg->hw_enabled && p_cfg->hw_powered) diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c index 3c5bee429105..6721cb1af5fe 100644 --- a/drivers/hwtracing/coresight/coresight-platform.c +++ b/drivers/hwtracing/coresight/coresight-platform.c @@ -293,6 +293,12 @@ static int of_get_coresight_platform_data(struct device *dev,
return 0;
}
+static inline const char *of_coresight_get_node_name(struct device *dev) +{
return dev->of_node->full_name;
+}
#else static inline int of_get_coresight_platform_data(struct device *dev, @@ -305,6 +311,11 @@ static inline int of_coresight_get_cpu(struct device *dev) { return -ENODEV; }
+static inline const char *of_coresight_get_node_name(struct device *dev) +{
return NULL;
+} #endif
#ifdef CONFIG_ACPI @@ -766,6 +777,18 @@ static inline int acpi_coresight_get_cpu(struct device *dev) } #endif
+const char *coresight_get_fwnode_name(struct device *dev) +{
const char *node_name = NULL;
struct fwnode_handle *fwnode = dev_fwnode(dev);
if (is_of_node(fwnode))
node_name = of_coresight_get_node_name(dev);
return node_name;
+} +EXPORT_SYMBOL_GPL(coresight_get_fwnode_name);
int coresight_get_cpu(struct device *dev) { if (is_of_node(dev->fwnode)) diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index aba6b789c969..4c176498a367 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -162,6 +162,13 @@ static inline int etm_readl_cp14(u32 off, unsigned int *val) { return 0; } static inline int etm_writel_cp14(u32 off, u32 val) { return 0; } #endif
+#ifdef CONFIG_CORESIGHT_CTI +extern void cti_add_assoc_to_csdev(struct coresight_device *csdev); +#else +static inline int cti_add_assoc_to_csdev(struct coresight_device *csdev) +{ return 0; } +#endif
/*
- Macros and inline functions to handle CoreSight UCI data and driver
- private data in AMBA ID table entries, and extract data values.
diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 64ff810394f9..52b294dd898e 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -216,6 +216,31 @@ void coresight_disclaim_device(void __iomem *base) CS_LOCK(base); }
+/* enable or disable an associated CTI device of the supplied CS device */ +static int +coresight_control_assoc_ectdev(struct coresight_device *csdev, bool enable) +{
int ect_ret = 0;
struct coresight_device *ect_csdev = csdev->ect_dev;
if (!ect_csdev)
return 0;
if (enable) {
if (ect_ops(ect_csdev)->enable)
ect_ret = ect_ops(ect_csdev)->enable(ect_csdev);
} else {
if (ect_ops(ect_csdev)->disable)
ect_ret = ect_ops(ect_csdev)->disable(ect_csdev);
}
/* output warning if ECT enable is preventing trace operation */
if (ect_ret)
dev_info(&csdev->dev, "Associated ECT device (%s) %s failed\n",
dev_name(&ect_csdev->dev), enable ? "enable" : "disable");
return ect_ret;
+}
static int coresight_enable_sink(struct coresight_device *csdev, u32 mode, void *data) { @@ -228,11 +253,15 @@ static int coresight_enable_sink(struct coresight_device *csdev, if (!sink_ops(csdev)->enable) return -EINVAL;
ret = sink_ops(csdev)->enable(csdev, mode, data);
ret = coresight_control_assoc_ectdev(csdev, true); if (ret) return ret;
ret = sink_ops(csdev)->enable(csdev, mode, data);
if (ret) {
coresight_control_assoc_ectdev(csdev, false);
return ret;
} csdev->enable = true;
return 0;
}
@@ -246,6 +275,7 @@ static void coresight_disable_sink(struct coresight_device *csdev) ret = sink_ops(csdev)->disable(csdev); if (ret) return;
coresight_control_assoc_ectdev(csdev, false); csdev->enable = false;
}
@@ -276,7 +306,14 @@ static int coresight_enable_link(struct coresight_device *csdev,
if (atomic_inc_return(&csdev->refcnt[refport]) == 1) { if (link_ops(csdev)->enable) {
ret = link_ops(csdev)->enable(csdev, inport, outport);
ret = coresight_control_assoc_ectdev(csdev, true);
if (!ret) {
ret = link_ops(csdev)->enable(csdev, inport,
outport);
if (ret)
coresight_control_assoc_ectdev(csdev,
false);
} if (ret) { atomic_dec(&csdev->refcnt[refport]); return ret;
@@ -316,8 +353,10 @@ static void coresight_disable_link(struct coresight_device *csdev, }
if (atomic_dec_return(&csdev->refcnt[refport]) == 0) {
if (link_ops(csdev)->disable)
if (link_ops(csdev)->disable) { link_ops(csdev)->disable(csdev, inport, outport);
coresight_control_assoc_ectdev(csdev, false);
} } for (i = 0; i < nr_conns; i++)
@@ -339,9 +378,14 @@ static int coresight_enable_source(struct coresight_device *csdev, u32 mode)
if (!csdev->enable) { if (source_ops(csdev)->enable) {
ret = source_ops(csdev)->enable(csdev, NULL, mode);
ret = coresight_control_assoc_ectdev(csdev, true); if (ret) return ret;
ret = source_ops(csdev)->enable(csdev, NULL, mode);
if (ret) {
coresight_control_assoc_ectdev(csdev, false);
return ret;
}; } csdev->enable = true; }
@@ -364,6 +408,7 @@ static bool coresight_disable_source(struct coresight_device *csdev) if (atomic_dec_return(csdev->refcnt) == 0) { if (source_ops(csdev)->disable) source_ops(csdev)->disable(csdev, NULL);
coresight_control_assoc_ectdev(csdev, false); csdev->enable = false; } return !csdev->enable;
@@ -1270,6 +1315,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
coresight_fixup_device_conns(csdev); coresight_fixup_orphan_conns(csdev);
cti_add_assoc_to_csdev(csdev); mutex_unlock(&coresight_mutex);
diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 2a23c3cdf8e4..ff97e9a7080a 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -163,6 +163,8 @@ struct coresight_connection {
activated but not yet enabled. Enabling for a _sink_
appens when a source has been selected for that it.
- @ea: Device attribute for sink representation under PMU directory.
- @ect_dev: Associated cross trigger device. Not part of the trace data
*/
path or connections.
struct coresight_device { struct coresight_platform_data *pdata; @@ -176,6 +178,8 @@ struct coresight_device { /* sink specific fields */ bool activated; /* true only if a sink is part of a path */ struct dev_ext_attribute *ea;
/* cross trigger handling */
struct coresight_device *ect_dev;
};
/* @@ -335,5 +339,6 @@ static inline void coresight_disclaim_device_unlocked(void __iomem *base) {} extern int coresight_get_cpu(struct device *dev);
struct coresight_platform_data *coresight_get_platform_data(struct device *dev); +extern const char *coresight_get_fwnode_name(struct device *dev);
#endif
2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
On Tue, 19 Nov 2019 at 08:50, Mike Leach mike.leach@linaro.org wrote:
Hi Mathieu,
On Thu, 3 Oct 2019 at 18:26, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Mon, Aug 19, 2019 at 10:13:54PM +0100, Mike Leach wrote:
The CoreSight subsystem enables a path of devices from source to sink. Any CTI devices associated with the path devices must be enabled at the same time.
This patch adds an associated coresight_device element to the main coresight device structure, and uses this to create associations between the CTI and other devices based on the device tree data. The associated device element is used to enable CTI in conjunction with the path elements.
CTI devices are reference counted so where a single CTI is associated with multiple elements on the path, it will be enabled on the first associated device enable, and disabled with the last associated device disable.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../coresight/coresight-cti-platform.c | 2 + drivers/hwtracing/coresight/coresight-cti.c | 87 +++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.h | 1 + .../hwtracing/coresight/coresight-platform.c | 23 +++++ drivers/hwtracing/coresight/coresight-priv.h | 7 ++ drivers/hwtracing/coresight/coresight.c | 56 ++++++++++-- include/linux/coresight.h | 5 ++ 7 files changed, 176 insertions(+), 5 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c index b7649f75f08b..c57ecbfd792d 100644 --- a/drivers/hwtracing/coresight/coresight-cti-platform.c +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -393,6 +393,7 @@ int of_get_coresight_cti_platform_data(struct device *dev,
return ret;
}
#else inline int of_get_coresight_cti_platform_data(struct device *dev, @@ -427,3 +428,4 @@ coresight_cti_get_platform_data(struct device *dev) error: return ERR_PTR(ret); }
diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 9b0441d8be61..927f58af92a2 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -450,6 +450,90 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, return err; }
+/*
- Look for a matching connection device name in the list of
- connections. If found then swap in the csdev name and return
- found.
- */
+static bool +cti_match_con_name(struct cti_device *ctidev, const char *node_name,
const char *csdev_name)
+{
struct cti_trig_con *trig_con;
list_for_each_entry(trig_con, &ctidev->trig_cons, node) {
if (trig_con->con_dev_name) {
if (!strcmp(node_name, trig_con->con_dev_name)) {
/* match: so swap in csdev name */
kfree(trig_con->con_dev_name);
trig_con->con_dev_name =
kstrdup(csdev_name, GFP_KERNEL);
return true;
}
}
}
return false;
+}
+/*
- Search the cti list to add an associated CTI into the supplied CS device
- This will set the association if CTI declared before the CS device
- */
+void cti_add_assoc_to_csdev(struct coresight_device *csdev) +{
struct cti_drvdata *ect_item;
struct cti_device *ctidev;
const char *node_name = NULL, *csdev_name;
/* protect the list */
mutex_lock(&ect_mutex);
There is no need to grab the mutex that early on. Please move to just before searching the list.
list_empty() in the ii () below is checking the list - so we do need the mutex here.
Yes, you are correct.
Thanks
Mike
/* exit if current is an ECT device.*/
if ((csdev->type == CORESIGHT_DEV_TYPE_ECT) || list_empty(&ect_net))
goto cti_add_done;
/* if we didn't find the csdev previously we used the fwnode name */
node_name = coresight_get_fwnode_name(csdev->dev.parent);
if (!node_name)
goto cti_add_done;
/* this is the name we want to use for the association */
csdev_name = dev_name(&csdev->dev);
/* for each CTI in list... */
list_for_each_entry(ect_item, &ect_net, node) {
ctidev = &ect_item->ctidev;
if (cti_match_con_name(ctidev, node_name, csdev_name)) {
/*
* if we found a matching name then update the
* association pointers.
*/
csdev->ect_dev = ect_item->csdev;
goto cti_add_done;
}
}
+cti_add_done:
mutex_unlock(&ect_mutex);
+} +EXPORT_SYMBOL_GPL(cti_add_assoc_to_csdev);
+/*
- Update the cross references where the associated device was found
- while we were building the connection info. This will occur if the
- assoc device was registered before the CTI.
- */
+static void cti_update_conn_xrefs(struct cti_drvdata *drvdata) +{
struct cti_trig_con *tc;
struct cti_device *ctidev = &drvdata->ctidev;
list_for_each_entry(tc, &ctidev->trig_cons, node) {
if (tc->con_dev)
tc->con_dev->ect_dev = drvdata->csdev;
}
+}
/** cti ect operations **/ int cti_enable(struct coresight_device *csdev) { @@ -585,6 +669,9 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) drvdata->csdev_release = drvdata->csdev->dev.release; drvdata->csdev->dev.release = cti_device_release;
/* set any cross references */
cti_update_conn_xrefs(drvdata);
/* all done - dec pm refcount */ pm_runtime_put(&adev->dev); dev_info(dev, "%s: CTI initialized\n", cti_desc.name);
diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index 865d3d0ffb11..90622f3be12b 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -224,6 +224,7 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, u32 channel_idx); struct coresight_platform_data * coresight_cti_get_platform_data(struct device *dev); +const char *coresight_cti_get_node_name(struct device *dev);
/* cti powered and enabled */ #define CTI_PWR_ENA(p_cfg) (p_cfg->hw_enabled && p_cfg->hw_powered) diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c index 3c5bee429105..6721cb1af5fe 100644 --- a/drivers/hwtracing/coresight/coresight-platform.c +++ b/drivers/hwtracing/coresight/coresight-platform.c @@ -293,6 +293,12 @@ static int of_get_coresight_platform_data(struct device *dev,
return 0;
}
+static inline const char *of_coresight_get_node_name(struct device *dev) +{
return dev->of_node->full_name;
+}
#else static inline int of_get_coresight_platform_data(struct device *dev, @@ -305,6 +311,11 @@ static inline int of_coresight_get_cpu(struct device *dev) { return -ENODEV; }
+static inline const char *of_coresight_get_node_name(struct device *dev) +{
return NULL;
+} #endif
#ifdef CONFIG_ACPI @@ -766,6 +777,18 @@ static inline int acpi_coresight_get_cpu(struct device *dev) } #endif
+const char *coresight_get_fwnode_name(struct device *dev) +{
const char *node_name = NULL;
struct fwnode_handle *fwnode = dev_fwnode(dev);
if (is_of_node(fwnode))
node_name = of_coresight_get_node_name(dev);
return node_name;
+} +EXPORT_SYMBOL_GPL(coresight_get_fwnode_name);
int coresight_get_cpu(struct device *dev) { if (is_of_node(dev->fwnode)) diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index aba6b789c969..4c176498a367 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -162,6 +162,13 @@ static inline int etm_readl_cp14(u32 off, unsigned int *val) { return 0; } static inline int etm_writel_cp14(u32 off, u32 val) { return 0; } #endif
+#ifdef CONFIG_CORESIGHT_CTI +extern void cti_add_assoc_to_csdev(struct coresight_device *csdev); +#else +static inline int cti_add_assoc_to_csdev(struct coresight_device *csdev) +{ return 0; } +#endif
/*
- Macros and inline functions to handle CoreSight UCI data and driver
- private data in AMBA ID table entries, and extract data values.
diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 64ff810394f9..52b294dd898e 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -216,6 +216,31 @@ void coresight_disclaim_device(void __iomem *base) CS_LOCK(base); }
+/* enable or disable an associated CTI device of the supplied CS device */ +static int +coresight_control_assoc_ectdev(struct coresight_device *csdev, bool enable) +{
int ect_ret = 0;
struct coresight_device *ect_csdev = csdev->ect_dev;
if (!ect_csdev)
return 0;
if (enable) {
if (ect_ops(ect_csdev)->enable)
ect_ret = ect_ops(ect_csdev)->enable(ect_csdev);
} else {
if (ect_ops(ect_csdev)->disable)
ect_ret = ect_ops(ect_csdev)->disable(ect_csdev);
}
/* output warning if ECT enable is preventing trace operation */
if (ect_ret)
dev_info(&csdev->dev, "Associated ECT device (%s) %s failed\n",
dev_name(&ect_csdev->dev), enable ? "enable" : "disable");
return ect_ret;
+}
static int coresight_enable_sink(struct coresight_device *csdev, u32 mode, void *data) { @@ -228,11 +253,15 @@ static int coresight_enable_sink(struct coresight_device *csdev, if (!sink_ops(csdev)->enable) return -EINVAL;
ret = sink_ops(csdev)->enable(csdev, mode, data);
ret = coresight_control_assoc_ectdev(csdev, true); if (ret) return ret;
ret = sink_ops(csdev)->enable(csdev, mode, data);
if (ret) {
coresight_control_assoc_ectdev(csdev, false);
return ret;
} csdev->enable = true;
return 0;
}
@@ -246,6 +275,7 @@ static void coresight_disable_sink(struct coresight_device *csdev) ret = sink_ops(csdev)->disable(csdev); if (ret) return;
coresight_control_assoc_ectdev(csdev, false); csdev->enable = false;
}
@@ -276,7 +306,14 @@ static int coresight_enable_link(struct coresight_device *csdev,
if (atomic_inc_return(&csdev->refcnt[refport]) == 1) { if (link_ops(csdev)->enable) {
ret = link_ops(csdev)->enable(csdev, inport, outport);
ret = coresight_control_assoc_ectdev(csdev, true);
if (!ret) {
ret = link_ops(csdev)->enable(csdev, inport,
outport);
if (ret)
coresight_control_assoc_ectdev(csdev,
false);
} if (ret) { atomic_dec(&csdev->refcnt[refport]); return ret;
@@ -316,8 +353,10 @@ static void coresight_disable_link(struct coresight_device *csdev, }
if (atomic_dec_return(&csdev->refcnt[refport]) == 0) {
if (link_ops(csdev)->disable)
if (link_ops(csdev)->disable) { link_ops(csdev)->disable(csdev, inport, outport);
coresight_control_assoc_ectdev(csdev, false);
} } for (i = 0; i < nr_conns; i++)
@@ -339,9 +378,14 @@ static int coresight_enable_source(struct coresight_device *csdev, u32 mode)
if (!csdev->enable) { if (source_ops(csdev)->enable) {
ret = source_ops(csdev)->enable(csdev, NULL, mode);
ret = coresight_control_assoc_ectdev(csdev, true); if (ret) return ret;
ret = source_ops(csdev)->enable(csdev, NULL, mode);
if (ret) {
coresight_control_assoc_ectdev(csdev, false);
return ret;
}; } csdev->enable = true; }
@@ -364,6 +408,7 @@ static bool coresight_disable_source(struct coresight_device *csdev) if (atomic_dec_return(csdev->refcnt) == 0) { if (source_ops(csdev)->disable) source_ops(csdev)->disable(csdev, NULL);
coresight_control_assoc_ectdev(csdev, false); csdev->enable = false; } return !csdev->enable;
@@ -1270,6 +1315,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
coresight_fixup_device_conns(csdev); coresight_fixup_orphan_conns(csdev);
cti_add_assoc_to_csdev(csdev); mutex_unlock(&coresight_mutex);
diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 2a23c3cdf8e4..ff97e9a7080a 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -163,6 +163,8 @@ struct coresight_connection {
activated but not yet enabled. Enabling for a _sink_
appens when a source has been selected for that it.
- @ea: Device attribute for sink representation under PMU directory.
- @ect_dev: Associated cross trigger device. Not part of the trace data
*/
path or connections.
struct coresight_device { struct coresight_platform_data *pdata; @@ -176,6 +178,8 @@ struct coresight_device { /* sink specific fields */ bool activated; /* true only if a sink is part of a path */ struct dev_ext_attribute *ea;
/* cross trigger handling */
struct coresight_device *ect_dev;
};
/* @@ -335,5 +339,6 @@ static inline void coresight_disclaim_device_unlocked(void __iomem *base) {} extern int coresight_get_cpu(struct device *dev);
struct coresight_platform_data *coresight_get_platform_data(struct device *dev); +extern const char *coresight_get_fwnode_name(struct device *dev);
#endif
2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
Dynamically adds sysfs attributes for all connections defined in the CTI.
Each connection has a triggers<N> sub-directory with name, in_signals, in_types, out_signals and out_types as read-only parameters in the directory. in_ or out_ parameters may be omitted if there are no in or out signals for the connection.
Additionally each device has a nr_cons and trigout_filtered parameter in the connections sub-directory. . This allows clients to explore the connection and trigger signal details without needing to refer to device tree or specification of the device.
Standardised type information is provided for certain common functions - e.g. snk_full for a trigger from a sink indicating full. Otherwise type defaults to genio.
Signed-off-by: Mike Leach mike.leach@linaro.org --- .../hwtracing/coresight/coresight-cti-sysfs.c | 343 +++++++++++++++++- drivers/hwtracing/coresight/coresight-cti.c | 13 +- drivers/hwtracing/coresight/coresight-cti.h | 6 + 3 files changed, 360 insertions(+), 2 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index dbbfd1de58b3..a7ae479ee2b9 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -829,7 +829,342 @@ static struct attribute *coresight_cti_channel_attrs[] = { NULL, };
-/* sysfs groups */ +/* Create the connections trigger groups and attrs dynamically */ + +/* + * Each connection has dynamic group + name, trigin/out sigs/types attrs, + * + each device has static nr_conns + filter attr + */ +static ssize_t trigout_filtered_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cti_config *cfg = &drvdata->config; + int size = 0, nr_trig_max = cfg->nr_trig_max; + unsigned long mask = cfg->trig_out_filter; + + if (mask) + size = bitmap_print_to_pagebuf(true, buf, &mask, nr_trig_max); + else + size = scnprintf(buf, PAGE_SIZE, "none\n"); + return size; +} +static DEVICE_ATTR_RO(trigout_filtered); + +static ssize_t nr_cons_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return scnprintf(buf, PAGE_SIZE, "%d\n", drvdata->ctidev.nr_trig_con); +} +static DEVICE_ATTR_RO(nr_cons); + +static struct attribute *coresight_cti_cons_attrs[] = { + &dev_attr_trigout_filtered.attr, + &dev_attr_nr_cons.attr, + NULL, +}; + +static ssize_t con_name_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr; + struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var; + + return scnprintf(buf, PAGE_SIZE, "%s\n", con->con_dev_name); +} + +static ssize_t trigin_sig_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr; + struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var; + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cti_config *cfg = &drvdata->config; + unsigned long mask = con->con_in->used_mask; + + return bitmap_print_to_pagebuf(true, buf, &mask, cfg->nr_trig_max); +} + +static ssize_t trigout_sig_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr; + struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var; + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cti_config *cfg = &drvdata->config; + unsigned long mask = con->con_out->used_mask; + + return bitmap_print_to_pagebuf(true, buf, &mask, cfg->nr_trig_max); +} + +/* convert a sig type id to a name */ +static const char * +cti_sig_type_name(struct cti_trig_con *con, int used_count, bool in) +{ + static const char * const sig_type_names[] = { + "genio", "intreq", "intack", "haltreq", "restartreq", + "pe_edbgreq", "pe_dbgrestart", "pe_ctiirq", "pe_pmuirq", + "pe_dbgtrigger", "etm_extout", "etm_extin", "snk_full", + "snk_acqcomp", "snk_flushcomp", "snk_flushin", "snk_trigin", + "stm_asyncout", "stm_tout_spte", "stm_tout_sw", "stm_tout_hete", + "stm_hwevent", "ela_tstart", "ela_tstop", "ela_dbgreq", + }; + int idx = 0; + struct cti_trig_grp *grp = in ? con->con_in : con->con_out; + + if (grp->sig_types) { + if (used_count < grp->nr_sigs) + idx = grp->sig_types[used_count]; + } + return sig_type_names[idx]; +} + +static ssize_t trigin_type_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr; + struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var; + + int sig_idx, used = 0, b_sz = PAGE_SIZE; + const char *name; + + for (sig_idx = 0; sig_idx < con->con_in->nr_sigs; sig_idx++) { + name = cti_sig_type_name(con, sig_idx, true); + used += scnprintf(buf+used, b_sz-used, "%s ", name); + } + used += scnprintf(buf+used, b_sz-used, "\n"); + return used; +} + +static ssize_t trigout_type_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr; + struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var; + + int sig_idx, used = 0, b_sz = PAGE_SIZE; + const char *name; + + for (sig_idx = 0; sig_idx < con->con_out->nr_sigs; sig_idx++) { + name = cti_sig_type_name(con, sig_idx, false); + used += scnprintf(buf+used, b_sz-used, "%s ", name); + } + used += scnprintf(buf+used, b_sz-used, "\n"); + return used; +} + +typedef ssize_t (*p_show_fn)(struct device *dev, struct device_attribute *attr, + char *buf); + +enum cti_conn_attr_type { + CTI_CON_ATTR_NAME, + CTI_CON_ATTR_TRIGIN_SIG, + CTI_CON_ATTR_TRIGOUT_SIG, + CTI_CON_ATTR_TRIGIN_TYPES, + CTI_CON_ATTR_TRIGOUT_TYPES +}; + +static p_show_fn show_fns[] = { + con_name_show, + trigin_sig_show, + trigout_sig_show, + trigin_type_show, + trigout_type_show, +}; + +static const char * const base_names[] = { + "name", + "in_signals", + "out_signals", + "in_types", + "out_types", +}; + +static int cti_create_con_sysfs_attr(struct cti_trig_con *con, + enum cti_conn_attr_type attr_type, + int attr_idx) +{ + struct dev_ext_attribute *dev_ext_attr = 0; + char *name = 0; + + dev_ext_attr = kzalloc(sizeof(struct dev_ext_attribute), GFP_KERNEL); + if (dev_ext_attr) { + name = kzalloc(sizeof(char) * 16, GFP_KERNEL); + if (name) { + /* fill out the underlying attribute struct */ + sprintf(name, "%s", base_names[attr_type]); + dev_ext_attr->attr.attr.name = name; + dev_ext_attr->attr.attr.mode = 0444; + + /* now the device_attribute struct */ + dev_ext_attr->attr.show = show_fns[attr_type]; + } else { + kfree(dev_ext_attr); + return -ENOMEM; + } + } else { + return -ENOMEM; + } + dev_ext_attr->var = con; + con->con_attrs[attr_idx] = dev_ext_attr; + return 0; +} + +/* number of static groups (5) declared below + null terminator */ +#define NR_STATIC_GROUPS 5 + +static struct attribute_group * +cti_create_con_sysfs_group(struct cti_device *ctidev, int con_idx) +{ + struct attribute_group *group = NULL; + + group = kzalloc(sizeof(struct attribute_group), GFP_KERNEL); + if (!group) + return NULL; + + group->name = kasprintf(GFP_KERNEL, "triggers%d", con_idx); + if (!group->name) { + kfree(group); + return NULL; + } + + ctidev->con_groups[con_idx + NR_STATIC_GROUPS] = group; + return group; +} + +/* dynamic attr - 5 per connection + null terminator */ +#define CTI_SYSFS_CONS_DYN_ATTR 5 + +/* create a triggers connection group and the attributes for that group */ +static int cti_create_con_attr_set(int con_idx, struct cti_device *ctidev, + struct cti_trig_con *con) +{ + struct attribute_group *attr_group = NULL; + int attr_idx = 0; + int err = -ENOMEM; + + attr_group = cti_create_con_sysfs_group(ctidev, con_idx); + if (!attr_group) + return -ENOMEM; + + con->con_attrs = kcalloc(CTI_SYSFS_CONS_DYN_ATTR + 1, + sizeof(struct dev_ext_attribute *), + GFP_KERNEL); + if (!con->con_attrs) + return -ENOMEM; + + err = cti_create_con_sysfs_attr(con, CTI_CON_ATTR_NAME, attr_idx++); + if (err) + return err; + + if (con->con_in->nr_sigs > 0) { + err = cti_create_con_sysfs_attr(con, CTI_CON_ATTR_TRIGIN_SIG, + attr_idx++); + if (err) + return err; + + err = cti_create_con_sysfs_attr(con, CTI_CON_ATTR_TRIGIN_TYPES, + attr_idx++); + if (err) + return err; + } + + if (con->con_in->nr_sigs > 0) { + err = cti_create_con_sysfs_attr(con, CTI_CON_ATTR_TRIGOUT_SIG, + attr_idx++); + if (err) + return err; + + err = cti_create_con_sysfs_attr(con, CTI_CON_ATTR_TRIGOUT_TYPES, + attr_idx++); + if (err) + return err; + } + attr_group->attrs = (struct attribute **)con->con_attrs; + return 0; +} + +/* create the array of group pointers for the CTI sysfs groups */ +int cti_create_cons_groups(struct cti_device *ctidev) +{ + int i, nr_groups; + + /* nr groups - dynamic + static + NULL terminator */ + nr_groups = ctidev->nr_trig_con + NR_STATIC_GROUPS + 1; + ctidev->con_groups = kcalloc(nr_groups, + sizeof(struct attribute_group *), + GFP_KERNEL); + if (!ctidev->con_groups) + return -ENOMEM; + + /* populate first locations with the static set of groups */ + for (i = 0; i < NR_STATIC_GROUPS; i++) + ctidev->con_groups[i] = coresight_cti_groups[i]; + + return 0; +} + +int cti_create_cons_sysfs(struct cti_drvdata *drvdata) +{ + struct cti_device *ctidev = &drvdata->ctidev; + int err, con_idx = 0; + struct cti_trig_con *tc = NULL; + + err = cti_create_cons_groups(ctidev); + if (err) + return err; + + /* add dynamic set for each connection */ + list_for_each_entry(tc, &ctidev->trig_cons, node) { + err = cti_create_con_attr_set(con_idx++, ctidev, tc); + if (err) + goto cons_sysfs_err; + } + return 0; + +cons_sysfs_err: + cti_destroy_cons_sysfs(ctidev); + return err; +} + +void cti_destroy_cons_attr_set(int con_idx, struct cti_device *ctidev, + struct cti_trig_con *con) +{ + int i; + + if (con->con_attrs) { + for (i = 0; i <= CTI_SYSFS_CONS_DYN_ATTR; i++) { + if (con->con_attrs[i]) { + kfree(con->con_attrs[i]->attr.attr.name); + kfree(con->con_attrs[i]); + } + } + kfree(con->con_attrs); + } + kfree(ctidev->con_groups[con_idx + NR_STATIC_GROUPS]); +} + +void cti_destroy_cons_sysfs(struct cti_device *ctidev) +{ + struct cti_trig_con *tc; + int con_idx = 0; + + list_for_each_entry(tc, &ctidev->trig_cons, node) { + cti_destroy_cons_attr_set(con_idx++, ctidev, tc); + } + kfree(ctidev->con_groups); +} + +/* attribute and group sysfs tables. */ static const struct attribute_group coresight_cti_group = { .attrs = coresight_cti_attrs, }; @@ -849,10 +1184,16 @@ static const struct attribute_group coresight_cti_channels_group = { .name = "channels", };
+static struct attribute_group coresight_cti_conns_group = { + .attrs = coresight_cti_cons_attrs, + .name = "connections", +}; + const struct attribute_group *coresight_cti_groups[] = { &coresight_cti_group, &coresight_cti_mgmt_group, &coresight_cti_regs_group, &coresight_cti_channels_group, + &coresight_cti_conns_group, NULL, }; diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 927f58af92a2..dce02f08ece1 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -571,6 +571,9 @@ static void cti_device_release(struct device *dev)
mutex_lock(&ect_mutex);
+ /* clear the dynamic sysfs associate with connections */ + cti_destroy_cons_sysfs(&drvdata->ctidev); + /* remove from the list */ list_for_each_entry_safe(ect_item, ect_tmp, &ect_net, node) { if (ect_item == drvdata) { @@ -647,12 +650,20 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) goto err_out; }
+ /* create dynamic attributes for connections */ + ret = cti_create_cons_sysfs(drvdata); + if (ret) { + pr_err("%s: create dynamic sysfs entries failed\n", + cti_desc.name); + goto err_out; + } + /* set up coresight component description */ cti_desc.pdata = pdata; cti_desc.type = CORESIGHT_DEV_TYPE_ECT; cti_desc.subtype.ect_subtype = CORESIGHT_DEV_SUBTYPE_ECT_CTI; cti_desc.ops = &cti_ops; - cti_desc.groups = coresight_cti_groups; + cti_desc.groups = drvdata->ctidev.con_groups; cti_desc.dev = dev; drvdata->csdev = coresight_register(&cti_desc); if (IS_ERR(drvdata->csdev)) { diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index 90622f3be12b..95ed026a2a61 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -74,6 +74,7 @@ struct cti_trig_grp { * @con_dev: coresight device connected to the CTI, NULL if not CS device * @con_dev_name: name of connected device (CS or CPU) * @node: entry node in list of connections. + * @con_attrs: Dynamic sysfs attributes specific to this connection. */ struct cti_trig_con { struct cti_trig_grp *con_in; @@ -81,6 +82,7 @@ struct cti_trig_con { struct coresight_device *con_dev; char *con_dev_name; struct list_head node; + struct dev_ext_attribute **con_attrs; };
/** @@ -91,12 +93,14 @@ struct cti_trig_con { * assumed there is a single CTM per SoC, ID 0). * @trig_cons: list of connections to this device. * @cpu: CPU ID if associated with CPU, -1 otherwise. + * @con_groups: Dynamic sysfs groups for trigger connections. */ struct cti_device { int nr_trig_con; u32 ctm_id; struct list_head trig_cons; int cpu; + const struct attribute_group **con_groups; };
/** @@ -222,6 +226,8 @@ int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op, u32 channel_idx); int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, u32 channel_idx); +int cti_create_cons_sysfs(struct cti_drvdata *drvdata); +void cti_destroy_cons_sysfs(struct cti_device *ctidev); struct coresight_platform_data * coresight_cti_get_platform_data(struct device *dev); const char *coresight_cti_get_node_name(struct device *dev);
On Mon, Aug 19, 2019 at 10:13:55PM +0100, Mike Leach wrote:
Dynamically adds sysfs attributes for all connections defined in the CTI.
Each connection has a triggers<N> sub-directory with name, in_signals, in_types, out_signals and out_types as read-only parameters in the directory. in_ or out_ parameters may be omitted if there are no in or out signals for the connection.
Additionally each device has a nr_cons and trigout_filtered parameter in the connections sub-directory. .
Please remove the '.'
This allows clients to explore the connection and trigger signal details without needing to refer to device tree or specification of the device.
Standardised type information is provided for certain common functions - e.g. snk_full for a trigger from a sink indicating full. Otherwise type defaults to genio.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-cti-sysfs.c | 343 +++++++++++++++++- drivers/hwtracing/coresight/coresight-cti.c | 13 +- drivers/hwtracing/coresight/coresight-cti.h | 6 + 3 files changed, 360 insertions(+), 2 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index dbbfd1de58b3..a7ae479ee2b9 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -829,7 +829,342 @@ static struct attribute *coresight_cti_channel_attrs[] = { NULL, }; -/* sysfs groups */ +/* Create the connections trigger groups and attrs dynamically */
+/*
- Each connection has dynamic group + name, trigin/out sigs/types attrs,
- each device has static nr_conns + filter attr
- */
+static ssize_t trigout_filtered_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *cfg = &drvdata->config;
- int size = 0, nr_trig_max = cfg->nr_trig_max;
- unsigned long mask = cfg->trig_out_filter;
- if (mask)
size = bitmap_print_to_pagebuf(true, buf, &mask, nr_trig_max);
- else
size = scnprintf(buf, PAGE_SIZE, "none\n");
The usual sysfs euristic is to not print anything when something isn't set.
- return size;
+} +static DEVICE_ATTR_RO(trigout_filtered);
+static ssize_t nr_cons_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- return scnprintf(buf, PAGE_SIZE, "%d\n", drvdata->ctidev.nr_trig_con);
+} +static DEVICE_ATTR_RO(nr_cons);
+static struct attribute *coresight_cti_cons_attrs[] = {
- &dev_attr_trigout_filtered.attr,
- &dev_attr_nr_cons.attr,
- NULL,
+};
+static ssize_t con_name_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr;
- struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
- return scnprintf(buf, PAGE_SIZE, "%s\n", con->con_dev_name);
+}
+static ssize_t trigin_sig_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr;
- struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *cfg = &drvdata->config;
- unsigned long mask = con->con_in->used_mask;
- return bitmap_print_to_pagebuf(true, buf, &mask, cfg->nr_trig_max);
+}
+static ssize_t trigout_sig_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr;
- struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *cfg = &drvdata->config;
- unsigned long mask = con->con_out->used_mask;
- return bitmap_print_to_pagebuf(true, buf, &mask, cfg->nr_trig_max);
+}
+/* convert a sig type id to a name */ +static const char * +cti_sig_type_name(struct cti_trig_con *con, int used_count, bool in) +{
- static const char * const sig_type_names[] = {
"genio", "intreq", "intack", "haltreq", "restartreq",
"pe_edbgreq", "pe_dbgrestart", "pe_ctiirq", "pe_pmuirq",
"pe_dbgtrigger", "etm_extout", "etm_extin", "snk_full",
"snk_acqcomp", "snk_flushcomp", "snk_flushin", "snk_trigin",
"stm_asyncout", "stm_tout_spte", "stm_tout_sw", "stm_tout_hete",
"stm_hwevent", "ela_tstart", "ela_tstop", "ela_dbgreq",
- };
This would likely be very confusing for someone new to the code. Please move sig_type_names[] to the top of the file and declare as follow:
static const char * const sig_type_names[] = { "genio", /* GEN_IO */ "intreq", /* GEN_INTREQ */ ...
Along with a comment that definitions follow the defines in coresight-cti-dt.h.
- int idx = 0;
- struct cti_trig_grp *grp = in ? con->con_in : con->con_out;
- if (grp->sig_types) {
if (used_count < grp->nr_sigs)
idx = grp->sig_types[used_count];
- }
- return sig_type_names[idx];
+}
+static ssize_t trigin_type_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr;
- struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
Extra newline
- int sig_idx, used = 0, b_sz = PAGE_SIZE;
- const char *name;
- for (sig_idx = 0; sig_idx < con->con_in->nr_sigs; sig_idx++) {
name = cti_sig_type_name(con, sig_idx, true);
used += scnprintf(buf+used, b_sz-used, "%s ", name);
A spaces is required on both side of the operator, for both '+' and '-'.
- }
- used += scnprintf(buf+used, b_sz-used, "\n");
Same comment as above
- return used;
+}
+static ssize_t trigout_type_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr;
- struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
Extra newline
- int sig_idx, used = 0, b_sz = PAGE_SIZE;
- const char *name;
- for (sig_idx = 0; sig_idx < con->con_out->nr_sigs; sig_idx++) {
name = cti_sig_type_name(con, sig_idx, false);
used += scnprintf(buf+used, b_sz-used, "%s ", name);
Same comment as above
- }
- used += scnprintf(buf+used, b_sz-used, "\n");
Same comment as above
- return used;
+}
+typedef ssize_t (*p_show_fn)(struct device *dev, struct device_attribute *attr,
char *buf);
+enum cti_conn_attr_type {
- CTI_CON_ATTR_NAME,
- CTI_CON_ATTR_TRIGIN_SIG,
- CTI_CON_ATTR_TRIGOUT_SIG,
- CTI_CON_ATTR_TRIGIN_TYPES,
- CTI_CON_ATTR_TRIGOUT_TYPES
+};
+static p_show_fn show_fns[] = {
- con_name_show,
- trigin_sig_show,
- trigout_sig_show,
- trigin_type_show,
- trigout_type_show,
+};
+static const char * const base_names[] = {
- "name",
- "in_signals",
- "out_signals",
- "in_types",
- "out_types",
+};
I would move all of these to the top of the file with sig_type_names[].
+static int cti_create_con_sysfs_attr(struct cti_trig_con *con,
enum cti_conn_attr_type attr_type,
int attr_idx)
+{
- struct dev_ext_attribute *dev_ext_attr = 0;
- char *name = 0;
- dev_ext_attr = kzalloc(sizeof(struct dev_ext_attribute), GFP_KERNEL);
- if (dev_ext_attr) {
name = kzalloc(sizeof(char) * 16, GFP_KERNEL);
if (name) {
/* fill out the underlying attribute struct */
sprintf(name, "%s", base_names[attr_type]);
Use kstrdup to allocate the exact size needed rather than having to settle for the biggest possible name. Doing so we can add any name without fear of a buffer overflow.
dev_ext_attr->attr.attr.name = name;
dev_ext_attr->attr.attr.mode = 0444;
/* now the device_attribute struct */
dev_ext_attr->attr.show = show_fns[attr_type];
} else {
kfree(dev_ext_attr);
return -ENOMEM;
}
- } else {
return -ENOMEM;
- }
- dev_ext_attr->var = con;
- con->con_attrs[attr_idx] = dev_ext_attr;
- return 0;
+}
+/* number of static groups (5) declared below + null terminator */ +#define NR_STATIC_GROUPS 5
We can't use ARRAY_SIZE() on coresight_cti_groups[] and at the same time we need to know the size of the array. I think the best way to do this is to move the #define to the top of the file and call it CORESIGHT_CTI_GROUPS_MAX. With that we can do "coresight_cti_groups[CORESIGHT_CTI_GROUPS_MAX] = {". That way anyone who wants to add to coresight_cti_groups needs to modify the define and things don't blow up in our face.
+static struct attribute_group * +cti_create_con_sysfs_group(struct cti_device *ctidev, int con_idx) +{
- struct attribute_group *group = NULL;
- group = kzalloc(sizeof(struct attribute_group), GFP_KERNEL);
- if (!group)
return NULL;
- group->name = kasprintf(GFP_KERNEL, "triggers%d", con_idx);
- if (!group->name) {
kfree(group);
return NULL;
- }
- ctidev->con_groups[con_idx + NR_STATIC_GROUPS] = group;
- return group;
+}
+/* dynamic attr - 5 per connection + null terminator */ +#define CTI_SYSFS_CONS_DYN_ATTR 5
This case is easier than the previous one. I would remove this and create a new CTI_CON_ATTR_TYPE_MAX in enum cti_connt_attr_type {} that can then be used in the declaration of p_show_fn show_fns[] and base_names[].
+/* create a triggers connection group and the attributes for that group */ +static int cti_create_con_attr_set(int con_idx, struct cti_device *ctidev,
struct cti_trig_con *con)
+{
- struct attribute_group *attr_group = NULL;
- int attr_idx = 0;
- int err = -ENOMEM;
- attr_group = cti_create_con_sysfs_group(ctidev, con_idx);
- if (!attr_group)
return -ENOMEM;
- con->con_attrs = kcalloc(CTI_SYSFS_CONS_DYN_ATTR + 1,
sizeof(struct dev_ext_attribute *),
GFP_KERNEL);
- if (!con->con_attrs)
return -ENOMEM;
- err = cti_create_con_sysfs_attr(con, CTI_CON_ATTR_NAME, attr_idx++);
- if (err)
return err;
- if (con->con_in->nr_sigs > 0) {
err = cti_create_con_sysfs_attr(con, CTI_CON_ATTR_TRIGIN_SIG,
attr_idx++);
if (err)
return err;
err = cti_create_con_sysfs_attr(con, CTI_CON_ATTR_TRIGIN_TYPES,
attr_idx++);
if (err)
return err;
- }
- if (con->con_in->nr_sigs > 0) {
err = cti_create_con_sysfs_attr(con, CTI_CON_ATTR_TRIGOUT_SIG,
attr_idx++);
if (err)
return err;
err = cti_create_con_sysfs_attr(con, CTI_CON_ATTR_TRIGOUT_TYPES,
attr_idx++);
if (err)
return err;
- }
- attr_group->attrs = (struct attribute **)con->con_attrs;
Did you see this being done somewhere? If so please share so that I can have a look. To me cti_trig_con::con_attrs need to be of type struct attribute **. In function cti_create_con_sysfs_attr() the last line becomes:
con->con_attrs[attr_idx] = &dev_ext_attr->attr.attr;
In the shows function the dev_ext_attribute can be reached using a container_of() like I did here:
https://elixir.bootlin.com/linux/latest/source/drivers/hwtracing/coresight/c...
- return 0;
+}
+/* create the array of group pointers for the CTI sysfs groups */ +int cti_create_cons_groups(struct cti_device *ctidev) +{
- int i, nr_groups;
- /* nr groups - dynamic + static + NULL terminator */
- nr_groups = ctidev->nr_trig_con + NR_STATIC_GROUPS + 1;
Following my recommendation on CORESIGHT_CTI_GROUPS_MAX, the above becomes:
/* nr groups - dynamic + static - NULL terminator */ nr_groups = ctidev->nr_trig_con + CORESIGHT_CTI_GROUPS_MAX - 1;
Probably best to declare a new variable and use it in the loop below as well.
- ctidev->con_groups = kcalloc(nr_groups,
sizeof(struct attribute_group *),
GFP_KERNEL);
- if (!ctidev->con_groups)
return -ENOMEM;
- /* populate first locations with the static set of groups */
- for (i = 0; i < NR_STATIC_GROUPS; i++)
ctidev->con_groups[i] = coresight_cti_groups[i];
- return 0;
+}
+int cti_create_cons_sysfs(struct cti_drvdata *drvdata) +{
- struct cti_device *ctidev = &drvdata->ctidev;
- int err, con_idx = 0;
- struct cti_trig_con *tc = NULL;
- err = cti_create_cons_groups(ctidev);
- if (err)
return err;
- /* add dynamic set for each connection */
- list_for_each_entry(tc, &ctidev->trig_cons, node) {
err = cti_create_con_attr_set(con_idx++, ctidev, tc);
if (err)
goto cons_sysfs_err;
- }
- return 0;
+cons_sysfs_err:
- cti_destroy_cons_sysfs(ctidev);
- return err;
+}
+void cti_destroy_cons_attr_set(int con_idx, struct cti_device *ctidev,
struct cti_trig_con *con)
+{
- int i;
- if (con->con_attrs) {
for (i = 0; i <= CTI_SYSFS_CONS_DYN_ATTR; i++) {
if (con->con_attrs[i]) {
kfree(con->con_attrs[i]->attr.attr.name);
kfree(con->con_attrs[i]);
}
}
kfree(con->con_attrs);
- }
- kfree(ctidev->con_groups[con_idx + NR_STATIC_GROUPS]);
+}
+void cti_destroy_cons_sysfs(struct cti_device *ctidev) +{
- struct cti_trig_con *tc;
- int con_idx = 0;
- list_for_each_entry(tc, &ctidev->trig_cons, node) {
cti_destroy_cons_attr_set(con_idx++, ctidev, tc);
- }
- kfree(ctidev->con_groups);
+}
+/* attribute and group sysfs tables. */ static const struct attribute_group coresight_cti_group = { .attrs = coresight_cti_attrs, }; @@ -849,10 +1184,16 @@ static const struct attribute_group coresight_cti_channels_group = { .name = "channels", }; +static struct attribute_group coresight_cti_conns_group = {
- .attrs = coresight_cti_cons_attrs,
- .name = "connections",
+};
const struct attribute_group *coresight_cti_groups[] = { &coresight_cti_group, &coresight_cti_mgmt_group, &coresight_cti_regs_group, &coresight_cti_channels_group,
- &coresight_cti_conns_group, NULL,
}; diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 927f58af92a2..dce02f08ece1 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -571,6 +571,9 @@ static void cti_device_release(struct device *dev) mutex_lock(&ect_mutex);
- /* clear the dynamic sysfs associate with connections */
- cti_destroy_cons_sysfs(&drvdata->ctidev);
- /* remove from the list */ list_for_each_entry_safe(ect_item, ect_tmp, &ect_net, node) { if (ect_item == drvdata) {
@@ -647,12 +650,20 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) goto err_out; }
- /* create dynamic attributes for connections */
- ret = cti_create_cons_sysfs(drvdata);
- if (ret) {
pr_err("%s: create dynamic sysfs entries failed\n",
cti_desc.name);
s/pr_err()/dev_info()
goto err_out;
- }
- /* set up coresight component description */ cti_desc.pdata = pdata; cti_desc.type = CORESIGHT_DEV_TYPE_ECT; cti_desc.subtype.ect_subtype = CORESIGHT_DEV_SUBTYPE_ECT_CTI; cti_desc.ops = &cti_ops;
- cti_desc.groups = coresight_cti_groups;
- cti_desc.groups = drvdata->ctidev.con_groups; cti_desc.dev = dev; drvdata->csdev = coresight_register(&cti_desc); if (IS_ERR(drvdata->csdev)) {
diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index 90622f3be12b..95ed026a2a61 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -74,6 +74,7 @@ struct cti_trig_grp {
- @con_dev: coresight device connected to the CTI, NULL if not CS device
- @con_dev_name: name of connected device (CS or CPU)
- @node: entry node in list of connections.
*/
- @con_attrs: Dynamic sysfs attributes specific to this connection.
struct cti_trig_con { struct cti_trig_grp *con_in; @@ -81,6 +82,7 @@ struct cti_trig_con { struct coresight_device *con_dev; char *con_dev_name; struct list_head node;
- struct dev_ext_attribute **con_attrs;
}; /** @@ -91,12 +93,14 @@ struct cti_trig_con {
assumed there is a single CTM per SoC, ID 0).
- @trig_cons: list of connections to this device.
- @cpu: CPU ID if associated with CPU, -1 otherwise.
*/
- @con_groups: Dynamic sysfs groups for trigger connections.
struct cti_device { int nr_trig_con; u32 ctm_id; struct list_head trig_cons; int cpu;
- const struct attribute_group **con_groups;
}; /** @@ -222,6 +226,8 @@ int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op, u32 channel_idx); int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, u32 channel_idx); +int cti_create_cons_sysfs(struct cti_drvdata *drvdata); +void cti_destroy_cons_sysfs(struct cti_device *ctidev); struct coresight_platform_data * coresight_cti_get_platform_data(struct device *dev); const char *coresight_cti_get_node_name(struct device *dev); -- 2.17.1
On Mon, Aug 19, 2019 at 10:13:55PM +0100, Mike Leach wrote:
Dynamically adds sysfs attributes for all connections defined in the CTI.
Each connection has a triggers<N> sub-directory with name, in_signals, in_types, out_signals and out_types as read-only parameters in the directory. in_ or out_ parameters may be omitted if there are no in or out signals for the connection.
Additionally each device has a nr_cons and trigout_filtered parameter in the connections sub-directory. . This allows clients to explore the connection and trigger signal details without needing to refer to device tree or specification of the device.
Standardised type information is provided for certain common functions - e.g. snk_full for a trigger from a sink indicating full. Otherwise type defaults to genio.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-cti-sysfs.c | 343 +++++++++++++++++- drivers/hwtracing/coresight/coresight-cti.c | 13 +- drivers/hwtracing/coresight/coresight-cti.h | 6 + 3 files changed, 360 insertions(+), 2 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index dbbfd1de58b3..a7ae479ee2b9 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -829,7 +829,342 @@ static struct attribute *coresight_cti_channel_attrs[] = { NULL, }; -/* sysfs groups */ +/* Create the connections trigger groups and attrs dynamically */
+/*
- Each connection has dynamic group + name, trigin/out sigs/types attrs,
- each device has static nr_conns + filter attr
- */
+static ssize_t trigout_filtered_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *cfg = &drvdata->config;
- int size = 0, nr_trig_max = cfg->nr_trig_max;
- unsigned long mask = cfg->trig_out_filter;
- if (mask)
size = bitmap_print_to_pagebuf(true, buf, &mask, nr_trig_max);
- else
size = scnprintf(buf, PAGE_SIZE, "none\n");
- return size;
+} +static DEVICE_ATTR_RO(trigout_filtered);
+static ssize_t nr_cons_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- return scnprintf(buf, PAGE_SIZE, "%d\n", drvdata->ctidev.nr_trig_con);
+} +static DEVICE_ATTR_RO(nr_cons);
+static struct attribute *coresight_cti_cons_attrs[] = {
- &dev_attr_trigout_filtered.attr,
- &dev_attr_nr_cons.attr,
After reviewing the CS sysfs topology set [1] I question the choice of lumping trigout_filtered under "connections" - there is very little semantic linking them together. Why not moving it under "channels" where it would show next to "trig_filter_enable"?
[1]. https://lists.linaro.org/pipermail/coresight/2019-August/003199.html
- NULL,
+};
+static ssize_t con_name_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr;
- struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
- return scnprintf(buf, PAGE_SIZE, "%s\n", con->con_dev_name);
+}
+static ssize_t trigin_sig_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr;
- struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *cfg = &drvdata->config;
- unsigned long mask = con->con_in->used_mask;
- return bitmap_print_to_pagebuf(true, buf, &mask, cfg->nr_trig_max);
+}
+static ssize_t trigout_sig_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr;
- struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *cfg = &drvdata->config;
- unsigned long mask = con->con_out->used_mask;
- return bitmap_print_to_pagebuf(true, buf, &mask, cfg->nr_trig_max);
+}
+/* convert a sig type id to a name */ +static const char * +cti_sig_type_name(struct cti_trig_con *con, int used_count, bool in) +{
- static const char * const sig_type_names[] = {
"genio", "intreq", "intack", "haltreq", "restartreq",
"pe_edbgreq", "pe_dbgrestart", "pe_ctiirq", "pe_pmuirq",
"pe_dbgtrigger", "etm_extout", "etm_extin", "snk_full",
"snk_acqcomp", "snk_flushcomp", "snk_flushin", "snk_trigin",
"stm_asyncout", "stm_tout_spte", "stm_tout_sw", "stm_tout_hete",
"stm_hwevent", "ela_tstart", "ela_tstop", "ela_dbgreq",
- };
- int idx = 0;
- struct cti_trig_grp *grp = in ? con->con_in : con->con_out;
- if (grp->sig_types) {
if (used_count < grp->nr_sigs)
idx = grp->sig_types[used_count];
- }
- return sig_type_names[idx];
+}
+static ssize_t trigin_type_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr;
- struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
- int sig_idx, used = 0, b_sz = PAGE_SIZE;
- const char *name;
- for (sig_idx = 0; sig_idx < con->con_in->nr_sigs; sig_idx++) {
name = cti_sig_type_name(con, sig_idx, true);
used += scnprintf(buf+used, b_sz-used, "%s ", name);
- }
- used += scnprintf(buf+used, b_sz-used, "\n");
- return used;
+}
+static ssize_t trigout_type_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr;
- struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
- int sig_idx, used = 0, b_sz = PAGE_SIZE;
- const char *name;
- for (sig_idx = 0; sig_idx < con->con_out->nr_sigs; sig_idx++) {
name = cti_sig_type_name(con, sig_idx, false);
used += scnprintf(buf+used, b_sz-used, "%s ", name);
- }
- used += scnprintf(buf+used, b_sz-used, "\n");
- return used;
+}
+typedef ssize_t (*p_show_fn)(struct device *dev, struct device_attribute *attr,
char *buf);
+enum cti_conn_attr_type {
- CTI_CON_ATTR_NAME,
- CTI_CON_ATTR_TRIGIN_SIG,
- CTI_CON_ATTR_TRIGOUT_SIG,
- CTI_CON_ATTR_TRIGIN_TYPES,
- CTI_CON_ATTR_TRIGOUT_TYPES
+};
+static p_show_fn show_fns[] = {
- con_name_show,
- trigin_sig_show,
- trigout_sig_show,
- trigin_type_show,
- trigout_type_show,
+};
+static const char * const base_names[] = {
- "name",
- "in_signals",
- "out_signals",
- "in_types",
- "out_types",
+};
+static int cti_create_con_sysfs_attr(struct cti_trig_con *con,
enum cti_conn_attr_type attr_type,
int attr_idx)
+{
- struct dev_ext_attribute *dev_ext_attr = 0;
- char *name = 0;
- dev_ext_attr = kzalloc(sizeof(struct dev_ext_attribute), GFP_KERNEL);
- if (dev_ext_attr) {
name = kzalloc(sizeof(char) * 16, GFP_KERNEL);
if (name) {
/* fill out the underlying attribute struct */
sprintf(name, "%s", base_names[attr_type]);
dev_ext_attr->attr.attr.name = name;
dev_ext_attr->attr.attr.mode = 0444;
/* now the device_attribute struct */
dev_ext_attr->attr.show = show_fns[attr_type];
} else {
kfree(dev_ext_attr);
return -ENOMEM;
}
- } else {
return -ENOMEM;
- }
- dev_ext_attr->var = con;
- con->con_attrs[attr_idx] = dev_ext_attr;
- return 0;
+}
+/* number of static groups (5) declared below + null terminator */ +#define NR_STATIC_GROUPS 5
+static struct attribute_group * +cti_create_con_sysfs_group(struct cti_device *ctidev, int con_idx) +{
- struct attribute_group *group = NULL;
- group = kzalloc(sizeof(struct attribute_group), GFP_KERNEL);
- if (!group)
return NULL;
- group->name = kasprintf(GFP_KERNEL, "triggers%d", con_idx);
- if (!group->name) {
kfree(group);
return NULL;
- }
- ctidev->con_groups[con_idx + NR_STATIC_GROUPS] = group;
- return group;
+}
+/* dynamic attr - 5 per connection + null terminator */ +#define CTI_SYSFS_CONS_DYN_ATTR 5
+/* create a triggers connection group and the attributes for that group */ +static int cti_create_con_attr_set(int con_idx, struct cti_device *ctidev,
struct cti_trig_con *con)
+{
- struct attribute_group *attr_group = NULL;
- int attr_idx = 0;
- int err = -ENOMEM;
- attr_group = cti_create_con_sysfs_group(ctidev, con_idx);
- if (!attr_group)
return -ENOMEM;
- con->con_attrs = kcalloc(CTI_SYSFS_CONS_DYN_ATTR + 1,
sizeof(struct dev_ext_attribute *),
GFP_KERNEL);
- if (!con->con_attrs)
return -ENOMEM;
- err = cti_create_con_sysfs_attr(con, CTI_CON_ATTR_NAME, attr_idx++);
- if (err)
return err;
- if (con->con_in->nr_sigs > 0) {
err = cti_create_con_sysfs_attr(con, CTI_CON_ATTR_TRIGIN_SIG,
attr_idx++);
if (err)
return err;
err = cti_create_con_sysfs_attr(con, CTI_CON_ATTR_TRIGIN_TYPES,
attr_idx++);
if (err)
return err;
- }
- if (con->con_in->nr_sigs > 0) {
err = cti_create_con_sysfs_attr(con, CTI_CON_ATTR_TRIGOUT_SIG,
attr_idx++);
if (err)
return err;
err = cti_create_con_sysfs_attr(con, CTI_CON_ATTR_TRIGOUT_TYPES,
attr_idx++);
if (err)
return err;
- }
- attr_group->attrs = (struct attribute **)con->con_attrs;
- return 0;
+}
+/* create the array of group pointers for the CTI sysfs groups */ +int cti_create_cons_groups(struct cti_device *ctidev) +{
- int i, nr_groups;
- /* nr groups - dynamic + static + NULL terminator */
- nr_groups = ctidev->nr_trig_con + NR_STATIC_GROUPS + 1;
- ctidev->con_groups = kcalloc(nr_groups,
sizeof(struct attribute_group *),
GFP_KERNEL);
- if (!ctidev->con_groups)
return -ENOMEM;
- /* populate first locations with the static set of groups */
- for (i = 0; i < NR_STATIC_GROUPS; i++)
ctidev->con_groups[i] = coresight_cti_groups[i];
- return 0;
+}
+int cti_create_cons_sysfs(struct cti_drvdata *drvdata) +{
- struct cti_device *ctidev = &drvdata->ctidev;
- int err, con_idx = 0;
- struct cti_trig_con *tc = NULL;
- err = cti_create_cons_groups(ctidev);
- if (err)
return err;
- /* add dynamic set for each connection */
- list_for_each_entry(tc, &ctidev->trig_cons, node) {
err = cti_create_con_attr_set(con_idx++, ctidev, tc);
if (err)
goto cons_sysfs_err;
- }
- return 0;
+cons_sysfs_err:
- cti_destroy_cons_sysfs(ctidev);
- return err;
+}
+void cti_destroy_cons_attr_set(int con_idx, struct cti_device *ctidev,
struct cti_trig_con *con)
+{
- int i;
- if (con->con_attrs) {
for (i = 0; i <= CTI_SYSFS_CONS_DYN_ATTR; i++) {
if (con->con_attrs[i]) {
kfree(con->con_attrs[i]->attr.attr.name);
kfree(con->con_attrs[i]);
}
}
kfree(con->con_attrs);
- }
- kfree(ctidev->con_groups[con_idx + NR_STATIC_GROUPS]);
+}
+void cti_destroy_cons_sysfs(struct cti_device *ctidev) +{
- struct cti_trig_con *tc;
- int con_idx = 0;
- list_for_each_entry(tc, &ctidev->trig_cons, node) {
cti_destroy_cons_attr_set(con_idx++, ctidev, tc);
- }
- kfree(ctidev->con_groups);
+}
+/* attribute and group sysfs tables. */ static const struct attribute_group coresight_cti_group = { .attrs = coresight_cti_attrs, }; @@ -849,10 +1184,16 @@ static const struct attribute_group coresight_cti_channels_group = { .name = "channels", }; +static struct attribute_group coresight_cti_conns_group = {
- .attrs = coresight_cti_cons_attrs,
- .name = "connections",
+};
const struct attribute_group *coresight_cti_groups[] = { &coresight_cti_group, &coresight_cti_mgmt_group, &coresight_cti_regs_group, &coresight_cti_channels_group,
- &coresight_cti_conns_group, NULL,
}; diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 927f58af92a2..dce02f08ece1 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -571,6 +571,9 @@ static void cti_device_release(struct device *dev) mutex_lock(&ect_mutex);
- /* clear the dynamic sysfs associate with connections */
- cti_destroy_cons_sysfs(&drvdata->ctidev);
- /* remove from the list */ list_for_each_entry_safe(ect_item, ect_tmp, &ect_net, node) { if (ect_item == drvdata) {
@@ -647,12 +650,20 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) goto err_out; }
- /* create dynamic attributes for connections */
- ret = cti_create_cons_sysfs(drvdata);
- if (ret) {
pr_err("%s: create dynamic sysfs entries failed\n",
cti_desc.name);
goto err_out;
- }
- /* set up coresight component description */ cti_desc.pdata = pdata; cti_desc.type = CORESIGHT_DEV_TYPE_ECT; cti_desc.subtype.ect_subtype = CORESIGHT_DEV_SUBTYPE_ECT_CTI; cti_desc.ops = &cti_ops;
- cti_desc.groups = coresight_cti_groups;
- cti_desc.groups = drvdata->ctidev.con_groups; cti_desc.dev = dev; drvdata->csdev = coresight_register(&cti_desc); if (IS_ERR(drvdata->csdev)) {
diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index 90622f3be12b..95ed026a2a61 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -74,6 +74,7 @@ struct cti_trig_grp {
- @con_dev: coresight device connected to the CTI, NULL if not CS device
- @con_dev_name: name of connected device (CS or CPU)
- @node: entry node in list of connections.
*/
- @con_attrs: Dynamic sysfs attributes specific to this connection.
struct cti_trig_con { struct cti_trig_grp *con_in; @@ -81,6 +82,7 @@ struct cti_trig_con { struct coresight_device *con_dev; char *con_dev_name; struct list_head node;
- struct dev_ext_attribute **con_attrs;
}; /** @@ -91,12 +93,14 @@ struct cti_trig_con {
assumed there is a single CTM per SoC, ID 0).
- @trig_cons: list of connections to this device.
- @cpu: CPU ID if associated with CPU, -1 otherwise.
*/
- @con_groups: Dynamic sysfs groups for trigger connections.
struct cti_device { int nr_trig_con; u32 ctm_id; struct list_head trig_cons; int cpu;
- const struct attribute_group **con_groups;
}; /** @@ -222,6 +226,8 @@ int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op, u32 channel_idx); int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, u32 channel_idx); +int cti_create_cons_sysfs(struct cti_drvdata *drvdata); +void cti_destroy_cons_sysfs(struct cti_device *ctidev); struct coresight_platform_data * coresight_cti_get_platform_data(struct device *dev); const char *coresight_cti_get_node_name(struct device *dev); -- 2.17.1
Fixed as suggested.
Thanks
Mike
On Thu, 3 Oct 2019 at 22:22, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Mon, Aug 19, 2019 at 10:13:55PM +0100, Mike Leach wrote:
Dynamically adds sysfs attributes for all connections defined in the CTI.
Each connection has a triggers<N> sub-directory with name, in_signals, in_types, out_signals and out_types as read-only parameters in the directory. in_ or out_ parameters may be omitted if there are no in or out signals for the connection.
Additionally each device has a nr_cons and trigout_filtered parameter in the connections sub-directory. . This allows clients to explore the connection and trigger signal details without needing to refer to device tree or specification of the device.
Standardised type information is provided for certain common functions - e.g. snk_full for a trigger from a sink indicating full. Otherwise type defaults to genio.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-cti-sysfs.c | 343 +++++++++++++++++- drivers/hwtracing/coresight/coresight-cti.c | 13 +- drivers/hwtracing/coresight/coresight-cti.h | 6 + 3 files changed, 360 insertions(+), 2 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index dbbfd1de58b3..a7ae479ee2b9 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -829,7 +829,342 @@ static struct attribute *coresight_cti_channel_attrs[] = { NULL, };
-/* sysfs groups */ +/* Create the connections trigger groups and attrs dynamically */
+/*
- Each connection has dynamic group + name, trigin/out sigs/types attrs,
- each device has static nr_conns + filter attr
- */
+static ssize_t trigout_filtered_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct cti_config *cfg = &drvdata->config;
int size = 0, nr_trig_max = cfg->nr_trig_max;
unsigned long mask = cfg->trig_out_filter;
if (mask)
size = bitmap_print_to_pagebuf(true, buf, &mask, nr_trig_max);
else
size = scnprintf(buf, PAGE_SIZE, "none\n");
return size;
+} +static DEVICE_ATTR_RO(trigout_filtered);
+static ssize_t nr_cons_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
return scnprintf(buf, PAGE_SIZE, "%d\n", drvdata->ctidev.nr_trig_con);
+} +static DEVICE_ATTR_RO(nr_cons);
+static struct attribute *coresight_cti_cons_attrs[] = {
&dev_attr_trigout_filtered.attr,
&dev_attr_nr_cons.attr,
After reviewing the CS sysfs topology set [1] I question the choice of lumping trigout_filtered under "connections" - there is very little semantic linking them together. Why not moving it under "channels" where it would show next to "trig_filter_enable"?
[1]. https://lists.linaro.org/pipermail/coresight/2019-August/003199.html
NULL,
+};
+static ssize_t con_name_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr;
struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
return scnprintf(buf, PAGE_SIZE, "%s\n", con->con_dev_name);
+}
+static ssize_t trigin_sig_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr;
struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct cti_config *cfg = &drvdata->config;
unsigned long mask = con->con_in->used_mask;
return bitmap_print_to_pagebuf(true, buf, &mask, cfg->nr_trig_max);
+}
+static ssize_t trigout_sig_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr;
struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct cti_config *cfg = &drvdata->config;
unsigned long mask = con->con_out->used_mask;
return bitmap_print_to_pagebuf(true, buf, &mask, cfg->nr_trig_max);
+}
+/* convert a sig type id to a name */ +static const char * +cti_sig_type_name(struct cti_trig_con *con, int used_count, bool in) +{
static const char * const sig_type_names[] = {
"genio", "intreq", "intack", "haltreq", "restartreq",
"pe_edbgreq", "pe_dbgrestart", "pe_ctiirq", "pe_pmuirq",
"pe_dbgtrigger", "etm_extout", "etm_extin", "snk_full",
"snk_acqcomp", "snk_flushcomp", "snk_flushin", "snk_trigin",
"stm_asyncout", "stm_tout_spte", "stm_tout_sw", "stm_tout_hete",
"stm_hwevent", "ela_tstart", "ela_tstop", "ela_dbgreq",
};
int idx = 0;
struct cti_trig_grp *grp = in ? con->con_in : con->con_out;
if (grp->sig_types) {
if (used_count < grp->nr_sigs)
idx = grp->sig_types[used_count];
}
return sig_type_names[idx];
+}
+static ssize_t trigin_type_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr;
struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
int sig_idx, used = 0, b_sz = PAGE_SIZE;
const char *name;
for (sig_idx = 0; sig_idx < con->con_in->nr_sigs; sig_idx++) {
name = cti_sig_type_name(con, sig_idx, true);
used += scnprintf(buf+used, b_sz-used, "%s ", name);
}
used += scnprintf(buf+used, b_sz-used, "\n");
return used;
+}
+static ssize_t trigout_type_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr;
struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
int sig_idx, used = 0, b_sz = PAGE_SIZE;
const char *name;
for (sig_idx = 0; sig_idx < con->con_out->nr_sigs; sig_idx++) {
name = cti_sig_type_name(con, sig_idx, false);
used += scnprintf(buf+used, b_sz-used, "%s ", name);
}
used += scnprintf(buf+used, b_sz-used, "\n");
return used;
+}
+typedef ssize_t (*p_show_fn)(struct device *dev, struct device_attribute *attr,
char *buf);
+enum cti_conn_attr_type {
CTI_CON_ATTR_NAME,
CTI_CON_ATTR_TRIGIN_SIG,
CTI_CON_ATTR_TRIGOUT_SIG,
CTI_CON_ATTR_TRIGIN_TYPES,
CTI_CON_ATTR_TRIGOUT_TYPES
+};
+static p_show_fn show_fns[] = {
con_name_show,
trigin_sig_show,
trigout_sig_show,
trigin_type_show,
trigout_type_show,
+};
+static const char * const base_names[] = {
"name",
"in_signals",
"out_signals",
"in_types",
"out_types",
+};
+static int cti_create_con_sysfs_attr(struct cti_trig_con *con,
enum cti_conn_attr_type attr_type,
int attr_idx)
+{
struct dev_ext_attribute *dev_ext_attr = 0;
char *name = 0;
dev_ext_attr = kzalloc(sizeof(struct dev_ext_attribute), GFP_KERNEL);
if (dev_ext_attr) {
name = kzalloc(sizeof(char) * 16, GFP_KERNEL);
if (name) {
/* fill out the underlying attribute struct */
sprintf(name, "%s", base_names[attr_type]);
dev_ext_attr->attr.attr.name = name;
dev_ext_attr->attr.attr.mode = 0444;
/* now the device_attribute struct */
dev_ext_attr->attr.show = show_fns[attr_type];
} else {
kfree(dev_ext_attr);
return -ENOMEM;
}
} else {
return -ENOMEM;
}
dev_ext_attr->var = con;
con->con_attrs[attr_idx] = dev_ext_attr;
return 0;
+}
+/* number of static groups (5) declared below + null terminator */ +#define NR_STATIC_GROUPS 5
+static struct attribute_group * +cti_create_con_sysfs_group(struct cti_device *ctidev, int con_idx) +{
struct attribute_group *group = NULL;
group = kzalloc(sizeof(struct attribute_group), GFP_KERNEL);
if (!group)
return NULL;
group->name = kasprintf(GFP_KERNEL, "triggers%d", con_idx);
if (!group->name) {
kfree(group);
return NULL;
}
ctidev->con_groups[con_idx + NR_STATIC_GROUPS] = group;
return group;
+}
+/* dynamic attr - 5 per connection + null terminator */ +#define CTI_SYSFS_CONS_DYN_ATTR 5
+/* create a triggers connection group and the attributes for that group */ +static int cti_create_con_attr_set(int con_idx, struct cti_device *ctidev,
struct cti_trig_con *con)
+{
struct attribute_group *attr_group = NULL;
int attr_idx = 0;
int err = -ENOMEM;
attr_group = cti_create_con_sysfs_group(ctidev, con_idx);
if (!attr_group)
return -ENOMEM;
con->con_attrs = kcalloc(CTI_SYSFS_CONS_DYN_ATTR + 1,
sizeof(struct dev_ext_attribute *),
GFP_KERNEL);
if (!con->con_attrs)
return -ENOMEM;
err = cti_create_con_sysfs_attr(con, CTI_CON_ATTR_NAME, attr_idx++);
if (err)
return err;
if (con->con_in->nr_sigs > 0) {
err = cti_create_con_sysfs_attr(con, CTI_CON_ATTR_TRIGIN_SIG,
attr_idx++);
if (err)
return err;
err = cti_create_con_sysfs_attr(con, CTI_CON_ATTR_TRIGIN_TYPES,
attr_idx++);
if (err)
return err;
}
if (con->con_in->nr_sigs > 0) {
err = cti_create_con_sysfs_attr(con, CTI_CON_ATTR_TRIGOUT_SIG,
attr_idx++);
if (err)
return err;
err = cti_create_con_sysfs_attr(con, CTI_CON_ATTR_TRIGOUT_TYPES,
attr_idx++);
if (err)
return err;
}
attr_group->attrs = (struct attribute **)con->con_attrs;
return 0;
+}
+/* create the array of group pointers for the CTI sysfs groups */ +int cti_create_cons_groups(struct cti_device *ctidev) +{
int i, nr_groups;
/* nr groups - dynamic + static + NULL terminator */
nr_groups = ctidev->nr_trig_con + NR_STATIC_GROUPS + 1;
ctidev->con_groups = kcalloc(nr_groups,
sizeof(struct attribute_group *),
GFP_KERNEL);
if (!ctidev->con_groups)
return -ENOMEM;
/* populate first locations with the static set of groups */
for (i = 0; i < NR_STATIC_GROUPS; i++)
ctidev->con_groups[i] = coresight_cti_groups[i];
return 0;
+}
+int cti_create_cons_sysfs(struct cti_drvdata *drvdata) +{
struct cti_device *ctidev = &drvdata->ctidev;
int err, con_idx = 0;
struct cti_trig_con *tc = NULL;
err = cti_create_cons_groups(ctidev);
if (err)
return err;
/* add dynamic set for each connection */
list_for_each_entry(tc, &ctidev->trig_cons, node) {
err = cti_create_con_attr_set(con_idx++, ctidev, tc);
if (err)
goto cons_sysfs_err;
}
return 0;
+cons_sysfs_err:
cti_destroy_cons_sysfs(ctidev);
return err;
+}
+void cti_destroy_cons_attr_set(int con_idx, struct cti_device *ctidev,
struct cti_trig_con *con)
+{
int i;
if (con->con_attrs) {
for (i = 0; i <= CTI_SYSFS_CONS_DYN_ATTR; i++) {
if (con->con_attrs[i]) {
kfree(con->con_attrs[i]->attr.attr.name);
kfree(con->con_attrs[i]);
}
}
kfree(con->con_attrs);
}
kfree(ctidev->con_groups[con_idx + NR_STATIC_GROUPS]);
+}
+void cti_destroy_cons_sysfs(struct cti_device *ctidev) +{
struct cti_trig_con *tc;
int con_idx = 0;
list_for_each_entry(tc, &ctidev->trig_cons, node) {
cti_destroy_cons_attr_set(con_idx++, ctidev, tc);
}
kfree(ctidev->con_groups);
+}
+/* attribute and group sysfs tables. */ static const struct attribute_group coresight_cti_group = { .attrs = coresight_cti_attrs, }; @@ -849,10 +1184,16 @@ static const struct attribute_group coresight_cti_channels_group = { .name = "channels", };
+static struct attribute_group coresight_cti_conns_group = {
.attrs = coresight_cti_cons_attrs,
.name = "connections",
+};
const struct attribute_group *coresight_cti_groups[] = { &coresight_cti_group, &coresight_cti_mgmt_group, &coresight_cti_regs_group, &coresight_cti_channels_group,
&coresight_cti_conns_group, NULL,
}; diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 927f58af92a2..dce02f08ece1 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -571,6 +571,9 @@ static void cti_device_release(struct device *dev)
mutex_lock(&ect_mutex);
/* clear the dynamic sysfs associate with connections */
cti_destroy_cons_sysfs(&drvdata->ctidev);
/* remove from the list */ list_for_each_entry_safe(ect_item, ect_tmp, &ect_net, node) { if (ect_item == drvdata) {
@@ -647,12 +650,20 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) goto err_out; }
/* create dynamic attributes for connections */
ret = cti_create_cons_sysfs(drvdata);
if (ret) {
pr_err("%s: create dynamic sysfs entries failed\n",
cti_desc.name);
goto err_out;
}
/* set up coresight component description */ cti_desc.pdata = pdata; cti_desc.type = CORESIGHT_DEV_TYPE_ECT; cti_desc.subtype.ect_subtype = CORESIGHT_DEV_SUBTYPE_ECT_CTI; cti_desc.ops = &cti_ops;
cti_desc.groups = coresight_cti_groups;
cti_desc.groups = drvdata->ctidev.con_groups; cti_desc.dev = dev; drvdata->csdev = coresight_register(&cti_desc); if (IS_ERR(drvdata->csdev)) {
diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index 90622f3be12b..95ed026a2a61 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -74,6 +74,7 @@ struct cti_trig_grp {
- @con_dev: coresight device connected to the CTI, NULL if not CS device
- @con_dev_name: name of connected device (CS or CPU)
- @node: entry node in list of connections.
*/
- @con_attrs: Dynamic sysfs attributes specific to this connection.
struct cti_trig_con { struct cti_trig_grp *con_in; @@ -81,6 +82,7 @@ struct cti_trig_con { struct coresight_device *con_dev; char *con_dev_name; struct list_head node;
struct dev_ext_attribute **con_attrs;
};
/** @@ -91,12 +93,14 @@ struct cti_trig_con {
assumed there is a single CTM per SoC, ID 0).
- @trig_cons: list of connections to this device.
- @cpu: CPU ID if associated with CPU, -1 otherwise.
*/
- @con_groups: Dynamic sysfs groups for trigger connections.
struct cti_device { int nr_trig_con; u32 ctm_id; struct list_head trig_cons; int cpu;
const struct attribute_group **con_groups;
};
/** @@ -222,6 +226,8 @@ int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op, u32 channel_idx); int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, u32 channel_idx); +int cti_create_cons_sysfs(struct cti_drvdata *drvdata); +void cti_destroy_cons_sysfs(struct cti_device *ctidev); struct coresight_platform_data * coresight_cti_get_platform_data(struct device *dev); const char *coresight_cti_get_node_name(struct device *dev); -- 2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
To allow the connections between coresight components to be represented in sysfs, generic methods for creating sysfs links between two coresight devices are added.
Signed-off-by: Mike Leach mike.leach@linaro.org --- drivers/hwtracing/coresight/coresight-priv.h | 2 + drivers/hwtracing/coresight/coresight.c | 73 ++++++++++++++++++++ include/linux/coresight.h | 18 +++++ 3 files changed, 93 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index 4c176498a367..d02e9d6b80ab 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -153,6 +153,8 @@ struct coresight_device *coresight_get_sink_by_id(u32 id); struct list_head *coresight_build_path(struct coresight_device *csdev, struct coresight_device *sink); void coresight_release_path(struct list_head *path); +int coresight_add_sysfs_link(struct coresight_sysfs_link *info); +void coresight_remove_sysfs_link(struct coresight_sysfs_link *info);
#ifdef CONFIG_CORESIGHT_SOURCE_ETM3X extern int etm_readl_cp14(u32 off, unsigned int *val); diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 52b294dd898e..5a07ba9e3a00 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -1032,6 +1032,79 @@ static void coresight_device_release(struct device *dev) kfree(csdev); }
+static int coresight_create_sysfs_link(struct kobject *from, + struct kobject *to, + const char *link_name, + const char *group_name) +{ + if (group_name) + return sysfs_add_link_to_group(from, group_name, + to, link_name); + else + return sysfs_create_link(from, to, link_name); +} + +static void coresight_delete_sysfs_link(struct kobject *kobj, + const char *link_name, + const char *group_name) +{ + if (group_name) + sysfs_remove_link_from_group(kobj, group_name, link_name); + else + sysfs_remove_link(kobj, link_name); +} + +int coresight_add_sysfs_link(struct coresight_sysfs_link *info) +{ + int ret = 0; + + if (!info) + return -EINVAL; + if (!info->orig || !info->target || + !info->orig_name || !info->target_name) + return -EINVAL; + + /* first link orig->target */ + ret = coresight_create_sysfs_link(&info->orig->dev.kobj, + &info->target->dev.kobj, + info->orig_name, + info->orig->sysfs_link_grp); + if (ret) + return ret; + + /* second link target->orig */ + ret = coresight_create_sysfs_link(&info->target->dev.kobj, + &info->orig->dev.kobj, + info->target_name, + info->target->sysfs_link_grp); + + /* error in second link - remove first */ + if (ret) { + coresight_delete_sysfs_link(&info->orig->dev.kobj, + info->orig_name, + info->orig->sysfs_link_grp); + } + + return ret; +} + +void coresight_remove_sysfs_link(struct coresight_sysfs_link *info) +{ + if (!info) + return; + if (!info->orig || !info->target || + !info->orig_name || !info->target_name) + return; + + coresight_delete_sysfs_link(&info->orig->dev.kobj, + info->orig_name, + info->orig->sysfs_link_grp); + + coresight_delete_sysfs_link(&info->target->dev.kobj, + info->target_name, + info->target->sysfs_link_grp); +} + static int coresight_orphan_match(struct device *dev, void *data) { int i; diff --git a/include/linux/coresight.h b/include/linux/coresight.h index ff97e9a7080a..cd0d92611be6 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -148,6 +148,20 @@ struct coresight_connection { struct coresight_device *child_dev; };
+/** + * struct coresight_sysfs_link - representation of a connection in sysfs. + * @orig: Originating (master) coresight device for the link. + * @orig_name: Name to use for the link orig->target. + * @target: Target (slave) coresight device for the link. + * @target_name: Name to use for the link target->orig. + */ +struct coresight_sysfs_link { + struct coresight_device *orig; + const char *orig_name; + struct coresight_device *target; + const char *target_name; +}; + /** * struct coresight_device - representation of a device as used by the framework * @pdata: Platform data with device connections associated to this device. @@ -165,6 +179,9 @@ struct coresight_connection { * @ea: Device attribute for sink representation under PMU directory. * @ect_dev: Associated cross trigger device. Not part of the trace data * path or connections. + * @sysfs_link_grp: Optional name for a group created to add sysfs links into + * on this device. Group must have been created on device + * registration. */ struct coresight_device { struct coresight_platform_data *pdata; @@ -180,6 +197,7 @@ struct coresight_device { struct dev_ext_attribute *ea; /* cross trigger handling */ struct coresight_device *ect_dev; + const char *sysfs_link_grp; };
/*
On Mon, Aug 19, 2019 at 10:13:56PM +0100, Mike Leach wrote:
To allow the connections between coresight components to be represented in sysfs, generic methods for creating sysfs links between two coresight devices are added.
This patch should be moved to the CS sysfs topology set [1]. That way coresight-sysfs.c can be created once and the content herein would have to be moved.
[1]. https://lists.linaro.org/pipermail/coresight/2019-August/003199.html
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/coresight-priv.h | 2 + drivers/hwtracing/coresight/coresight.c | 73 ++++++++++++++++++++ include/linux/coresight.h | 18 +++++ 3 files changed, 93 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index 4c176498a367..d02e9d6b80ab 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -153,6 +153,8 @@ struct coresight_device *coresight_get_sink_by_id(u32 id); struct list_head *coresight_build_path(struct coresight_device *csdev, struct coresight_device *sink); void coresight_release_path(struct list_head *path); +int coresight_add_sysfs_link(struct coresight_sysfs_link *info); +void coresight_remove_sysfs_link(struct coresight_sysfs_link *info); #ifdef CONFIG_CORESIGHT_SOURCE_ETM3X extern int etm_readl_cp14(u32 off, unsigned int *val); diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 52b294dd898e..5a07ba9e3a00 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -1032,6 +1032,79 @@ static void coresight_device_release(struct device *dev) kfree(csdev); } +static int coresight_create_sysfs_link(struct kobject *from,
struct kobject *to,
const char *link_name,
const char *group_name)
+{
- if (group_name)
return sysfs_add_link_to_group(from, group_name,
to, link_name);
- else
return sysfs_create_link(from, to, link_name);
I would mandate new links to go under "connections" and nothing else, hence no need for sysfs_create_link().
+}
+static void coresight_delete_sysfs_link(struct kobject *kobj,
const char *link_name,
const char *group_name)
+{
- if (group_name)
sysfs_remove_link_from_group(kobj, group_name, link_name);
- else
sysfs_remove_link(kobj, link_name);
Same as above.
+}
+int coresight_add_sysfs_link(struct coresight_sysfs_link *info) +{
- int ret = 0;
- if (!info)
return -EINVAL;
- if (!info->orig || !info->target ||
!info->orig_name || !info->target_name)
return -EINVAL;
- /* first link orig->target */
- ret = coresight_create_sysfs_link(&info->orig->dev.kobj,
&info->target->dev.kobj,
info->orig_name,
info->orig->sysfs_link_grp);
- if (ret)
return ret;
- /* second link target->orig */
- ret = coresight_create_sysfs_link(&info->target->dev.kobj,
&info->orig->dev.kobj,
info->target_name,
info->target->sysfs_link_grp);
- /* error in second link - remove first */
- if (ret) {
coresight_delete_sysfs_link(&info->orig->dev.kobj,
info->orig_name,
info->orig->sysfs_link_grp);
- }
- return ret;
+}
+void coresight_remove_sysfs_link(struct coresight_sysfs_link *info) +{
- if (!info)
return;
- if (!info->orig || !info->target ||
!info->orig_name || !info->target_name)
return;
- coresight_delete_sysfs_link(&info->orig->dev.kobj,
info->orig_name,
info->orig->sysfs_link_grp);
- coresight_delete_sysfs_link(&info->target->dev.kobj,
info->target_name,
info->target->sysfs_link_grp);
+}
static int coresight_orphan_match(struct device *dev, void *data) { int i; diff --git a/include/linux/coresight.h b/include/linux/coresight.h index ff97e9a7080a..cd0d92611be6 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -148,6 +148,20 @@ struct coresight_connection { struct coresight_device *child_dev; }; +/**
- struct coresight_sysfs_link - representation of a connection in sysfs.
- @orig: Originating (master) coresight device for the link.
- @orig_name: Name to use for the link orig->target.
- @target: Target (slave) coresight device for the link.
- @target_name: Name to use for the link target->orig.
- */
+struct coresight_sysfs_link {
- struct coresight_device *orig;
- const char *orig_name;
- struct coresight_device *target;
- const char *target_name;
+};
/**
- struct coresight_device - representation of a device as used by the framework
- @pdata: Platform data with device connections associated to this device.
@@ -165,6 +179,9 @@ struct coresight_connection {
- @ea: Device attribute for sink representation under PMU directory.
- @ect_dev: Associated cross trigger device. Not part of the trace data
path or connections.
- @sysfs_link_grp: Optional name for a group created to add sysfs links into
on this device. Group must have been created on device
*/
registration.
struct coresight_device { struct coresight_platform_data *pdata; @@ -180,6 +197,7 @@ struct coresight_device { struct dev_ext_attribute *ea; /* cross trigger handling */ struct coresight_device *ect_dev;
- const char *sysfs_link_grp;
Do we need this at all? From what I see in this set and the CS sysfs topology set it will always be "connections" and we don't want this to change since sysfs is considered to be an ABI.
}; /* -- 2.17.1
Hi Mathieu,
This patch and next moved to follow up set that deals with sysfs links all in one go.
Regards
Mike
On Thu, 3 Oct 2019 at 22:37, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Mon, Aug 19, 2019 at 10:13:56PM +0100, Mike Leach wrote:
To allow the connections between coresight components to be represented in sysfs, generic methods for creating sysfs links between two coresight devices are added.
This patch should be moved to the CS sysfs topology set [1]. That way coresight-sysfs.c can be created once and the content herein would have to be moved.
[1]. https://lists.linaro.org/pipermail/coresight/2019-August/003199.html
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/coresight-priv.h | 2 + drivers/hwtracing/coresight/coresight.c | 73 ++++++++++++++++++++ include/linux/coresight.h | 18 +++++ 3 files changed, 93 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index 4c176498a367..d02e9d6b80ab 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -153,6 +153,8 @@ struct coresight_device *coresight_get_sink_by_id(u32 id); struct list_head *coresight_build_path(struct coresight_device *csdev, struct coresight_device *sink); void coresight_release_path(struct list_head *path); +int coresight_add_sysfs_link(struct coresight_sysfs_link *info); +void coresight_remove_sysfs_link(struct coresight_sysfs_link *info);
#ifdef CONFIG_CORESIGHT_SOURCE_ETM3X extern int etm_readl_cp14(u32 off, unsigned int *val); diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 52b294dd898e..5a07ba9e3a00 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -1032,6 +1032,79 @@ static void coresight_device_release(struct device *dev) kfree(csdev); }
+static int coresight_create_sysfs_link(struct kobject *from,
struct kobject *to,
const char *link_name,
const char *group_name)
+{
if (group_name)
return sysfs_add_link_to_group(from, group_name,
to, link_name);
else
return sysfs_create_link(from, to, link_name);
I would mandate new links to go under "connections" and nothing else, hence no need for sysfs_create_link().
+}
+static void coresight_delete_sysfs_link(struct kobject *kobj,
const char *link_name,
const char *group_name)
+{
if (group_name)
sysfs_remove_link_from_group(kobj, group_name, link_name);
else
sysfs_remove_link(kobj, link_name);
Same as above.
+}
+int coresight_add_sysfs_link(struct coresight_sysfs_link *info) +{
int ret = 0;
if (!info)
return -EINVAL;
if (!info->orig || !info->target ||
!info->orig_name || !info->target_name)
return -EINVAL;
/* first link orig->target */
ret = coresight_create_sysfs_link(&info->orig->dev.kobj,
&info->target->dev.kobj,
info->orig_name,
info->orig->sysfs_link_grp);
if (ret)
return ret;
/* second link target->orig */
ret = coresight_create_sysfs_link(&info->target->dev.kobj,
&info->orig->dev.kobj,
info->target_name,
info->target->sysfs_link_grp);
/* error in second link - remove first */
if (ret) {
coresight_delete_sysfs_link(&info->orig->dev.kobj,
info->orig_name,
info->orig->sysfs_link_grp);
}
return ret;
+}
+void coresight_remove_sysfs_link(struct coresight_sysfs_link *info) +{
if (!info)
return;
if (!info->orig || !info->target ||
!info->orig_name || !info->target_name)
return;
coresight_delete_sysfs_link(&info->orig->dev.kobj,
info->orig_name,
info->orig->sysfs_link_grp);
coresight_delete_sysfs_link(&info->target->dev.kobj,
info->target_name,
info->target->sysfs_link_grp);
+}
static int coresight_orphan_match(struct device *dev, void *data) { int i; diff --git a/include/linux/coresight.h b/include/linux/coresight.h index ff97e9a7080a..cd0d92611be6 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -148,6 +148,20 @@ struct coresight_connection { struct coresight_device *child_dev; };
+/**
- struct coresight_sysfs_link - representation of a connection in sysfs.
- @orig: Originating (master) coresight device for the link.
- @orig_name: Name to use for the link orig->target.
- @target: Target (slave) coresight device for the link.
- @target_name: Name to use for the link target->orig.
- */
+struct coresight_sysfs_link {
struct coresight_device *orig;
const char *orig_name;
struct coresight_device *target;
const char *target_name;
+};
/**
- struct coresight_device - representation of a device as used by the framework
- @pdata: Platform data with device connections associated to this device.
@@ -165,6 +179,9 @@ struct coresight_connection {
- @ea: Device attribute for sink representation under PMU directory.
- @ect_dev: Associated cross trigger device. Not part of the trace data
path or connections.
- @sysfs_link_grp: Optional name for a group created to add sysfs links into
on this device. Group must have been created on device
*/
registration.
struct coresight_device { struct coresight_platform_data *pdata; @@ -180,6 +197,7 @@ struct coresight_device { struct dev_ext_attribute *ea; /* cross trigger handling */ struct coresight_device *ect_dev;
const char *sysfs_link_grp;
Do we need this at all? From what I see in this set and the CS sysfs topology set it will always be "connections" and we don't want this to change since sysfs is considered to be an ABI.
};
/*
2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
Adds in sysfs links for connections where the connected device is another coresight device. This allows examination of the coresight topology.
Non-coresight connections remain just as a reference name.
Signed-off-by: Mike Leach mike.leach@linaro.org --- drivers/hwtracing/coresight/coresight-cti.c | 46 +++++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index dce02f08ece1..639f5ea8e905 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -450,6 +450,37 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, return err; }
+static void cti_add_sysfs_link(struct cti_drvdata *drvdata, + struct cti_trig_con *tc) +{ + struct coresight_sysfs_link link_info; + + link_info.orig = drvdata->csdev; + link_info.orig_name = tc->con_dev_name; + link_info.target = tc->con_dev; + link_info.target_name = dev_name(&drvdata->csdev->dev); + coresight_add_sysfs_link(&link_info); +} + +static void cti_remove_all_sysfs_links(struct cti_drvdata *drvdata) +{ + struct cti_trig_con *tc; + struct cti_device *ctidev = &drvdata->ctidev; + struct coresight_sysfs_link link_info; + + /* origin device and target link name constant for this cti */ + link_info.orig = drvdata->csdev; + link_info.target_name = dev_name(&drvdata->csdev->dev); + + list_for_each_entry(tc, &ctidev->trig_cons, node) { + if (tc->con_dev) { + link_info.target = tc->con_dev; + link_info.orig_name = tc->con_dev_name; + coresight_remove_sysfs_link(&link_info); + } + } +} + /* * Look for a matching connection device name in the list of * connections. If found then swap in the csdev name and return @@ -457,7 +488,7 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, */ static bool cti_match_con_name(struct cti_device *ctidev, const char *node_name, - const char *csdev_name) + const char *csdev_name, struct cti_trig_con **tc) { struct cti_trig_con *trig_con;
@@ -468,6 +499,7 @@ cti_match_con_name(struct cti_device *ctidev, const char *node_name, kfree(trig_con->con_dev_name); trig_con->con_dev_name = kstrdup(csdev_name, GFP_KERNEL); + *tc = trig_con; return true; } } @@ -484,6 +516,7 @@ void cti_add_assoc_to_csdev(struct coresight_device *csdev) struct cti_drvdata *ect_item; struct cti_device *ctidev; const char *node_name = NULL, *csdev_name; + struct cti_trig_con *tc = NULL;
/* protect the list */ mutex_lock(&ect_mutex); @@ -504,12 +537,14 @@ void cti_add_assoc_to_csdev(struct coresight_device *csdev) /* for each CTI in list... */ list_for_each_entry(ect_item, &ect_net, node) { ctidev = &ect_item->ctidev; - if (cti_match_con_name(ctidev, node_name, csdev_name)) { + if (cti_match_con_name(ctidev, node_name, csdev_name, &tc)) { /* * if we found a matching name then update the * association pointers. */ csdev->ect_dev = ect_item->csdev; + tc->con_dev = csdev; + cti_add_sysfs_link(ect_item, tc); goto cti_add_done; } } @@ -529,8 +564,10 @@ static void cti_update_conn_xrefs(struct cti_drvdata *drvdata) struct cti_device *ctidev = &drvdata->ctidev;
list_for_each_entry(tc, &ctidev->trig_cons, node) { - if (tc->con_dev) + if (tc->con_dev) { tc->con_dev->ect_dev = drvdata->csdev; + cti_add_sysfs_link(drvdata, tc); + } } }
@@ -572,6 +609,7 @@ static void cti_device_release(struct device *dev) mutex_lock(&ect_mutex);
/* clear the dynamic sysfs associate with connections */ + cti_remove_all_sysfs_links(drvdata); cti_destroy_cons_sysfs(&drvdata->ctidev);
/* remove from the list */ @@ -681,6 +719,8 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) drvdata->csdev->dev.release = cti_device_release;
/* set any cross references */ + drvdata->csdev->sysfs_link_grp = + devm_kasprintf(dev, GFP_KERNEL, "connections"); cti_update_conn_xrefs(drvdata);
/* all done - dec pm refcount */
On Mon, Aug 19, 2019 at 10:13:57PM +0100, Mike Leach wrote:
Adds in sysfs links for connections where the connected device is another coresight device. This allows examination of the coresight topology.
Non-coresight connections remain just as a reference name.
I am puzzled about the above line and as such I suspect other reviewers will be too. Please expand a little bit more. As with the previous patch I would move this to the CS sysfs topology set.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/coresight-cti.c | 46 +++++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index dce02f08ece1..639f5ea8e905 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -450,6 +450,37 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, return err; } +static void cti_add_sysfs_link(struct cti_drvdata *drvdata,
struct cti_trig_con *tc)
+{
- struct coresight_sysfs_link link_info;
- link_info.orig = drvdata->csdev;
- link_info.orig_name = tc->con_dev_name;
- link_info.target = tc->con_dev;
- link_info.target_name = dev_name(&drvdata->csdev->dev);
- coresight_add_sysfs_link(&link_info);
+}
+static void cti_remove_all_sysfs_links(struct cti_drvdata *drvdata) +{
- struct cti_trig_con *tc;
- struct cti_device *ctidev = &drvdata->ctidev;
- struct coresight_sysfs_link link_info;
- /* origin device and target link name constant for this cti */
- link_info.orig = drvdata->csdev;
- link_info.target_name = dev_name(&drvdata->csdev->dev);
- list_for_each_entry(tc, &ctidev->trig_cons, node) {
if (tc->con_dev) {
link_info.target = tc->con_dev;
link_info.orig_name = tc->con_dev_name;
coresight_remove_sysfs_link(&link_info);
}
- }
+}
/*
- Look for a matching connection device name in the list of
- connections. If found then swap in the csdev name and return
@@ -457,7 +488,7 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, */ static bool cti_match_con_name(struct cti_device *ctidev, const char *node_name,
const char *csdev_name)
const char *csdev_name, struct cti_trig_con **tc)
{ struct cti_trig_con *trig_con; @@ -468,6 +499,7 @@ cti_match_con_name(struct cti_device *ctidev, const char *node_name, kfree(trig_con->con_dev_name); trig_con->con_dev_name = kstrdup(csdev_name, GFP_KERNEL);
}*tc = trig_con; return true; }
@@ -484,6 +516,7 @@ void cti_add_assoc_to_csdev(struct coresight_device *csdev) struct cti_drvdata *ect_item; struct cti_device *ctidev; const char *node_name = NULL, *csdev_name;
- struct cti_trig_con *tc = NULL;
/* protect the list */ mutex_lock(&ect_mutex); @@ -504,12 +537,14 @@ void cti_add_assoc_to_csdev(struct coresight_device *csdev) /* for each CTI in list... */ list_for_each_entry(ect_item, &ect_net, node) { ctidev = &ect_item->ctidev;
if (cti_match_con_name(ctidev, node_name, csdev_name)) {
if (cti_match_con_name(ctidev, node_name, csdev_name, &tc)) { /* * if we found a matching name then update the * association pointers. */ csdev->ect_dev = ect_item->csdev;
tc->con_dev = csdev;
} }cti_add_sysfs_link(ect_item, tc); goto cti_add_done;
@@ -529,8 +564,10 @@ static void cti_update_conn_xrefs(struct cti_drvdata *drvdata) struct cti_device *ctidev = &drvdata->ctidev; list_for_each_entry(tc, &ctidev->trig_cons, node) {
if (tc->con_dev)
if (tc->con_dev) { tc->con_dev->ect_dev = drvdata->csdev;
cti_add_sysfs_link(drvdata, tc);
}}
} @@ -572,6 +609,7 @@ static void cti_device_release(struct device *dev) mutex_lock(&ect_mutex); /* clear the dynamic sysfs associate with connections */
- cti_remove_all_sysfs_links(drvdata); cti_destroy_cons_sysfs(&drvdata->ctidev);
/* remove from the list */ @@ -681,6 +719,8 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) drvdata->csdev->dev.release = cti_device_release; /* set any cross references */
- drvdata->csdev->sysfs_link_grp =
cti_update_conn_xrefs(drvdata);devm_kasprintf(dev, GFP_KERNEL, "connections");
/* all done - dec pm refcount */ -- 2.17.1
Adds system and CPU bound CTI definitions for Qualcom msm8916 platform (Dragonboard DB410C). System CTIs 2-11 are omitted as no information available at present.
Signed-off-by: Mike Leach mike.leach@linaro.org --- arch/arm64/boot/dts/qcom/msm8916.dtsi | 85 +++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index 5ea9fb8f2f87..9589fc2cba22 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -8,6 +8,7 @@ #include <dt-bindings/reset/qcom,gcc-msm8916.h> #include <dt-bindings/clock/qcom,rpmcc.h> #include <dt-bindings/thermal/thermal.h> +#include <dt-bindings/arm/coresight-cti-dt.h>
/ { interrupt-parent = <&intc>; @@ -1357,7 +1358,7 @@ cpu = <&CPU3>; };
- etm@85c000 { + etm0: etm@85c000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0x85c000 0x1000>;
@@ -1375,7 +1376,7 @@ }; };
- etm@85d000 { + etm1: etm@85d000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0x85d000 0x1000>;
@@ -1393,7 +1394,7 @@ }; };
- etm@85e000 { + etm2: etm@85e000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0x85e000 0x1000>;
@@ -1411,7 +1412,7 @@ }; };
- etm@85f000 { + etm3: etm@85f000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0x85f000 0x1000>;
@@ -1429,6 +1430,82 @@ }; };
+ /* System CTIs */ + /* CTI 0 - TMC connections */ + cti@810000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x810000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + /* CTI 1 - TPIU connections */ + cti@811000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x811000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + /* CTIs 2-11 - no information - not instantiated */ + + /* Core CTIs; CTIs 12-15 */ + /* CTI - CPU-0 */ + cti@858000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x858000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>; + clock-names = "apb_pclk"; + + arm,cti-v8-arch; + cpu = <&CPU0>; + arm,cs-dev-assoc = <&etm0>; + + }; + + /* CTI - CPU-1 */ + cti@859000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x859000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>; + clock-names = "apb_pclk"; + + arm,cti-v8-arch; + cpu = <&CPU1>; + arm,cs-dev-assoc = <&etm1>; + }; + + /* CTI - CPU-2 */ + cti@85a000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x85a000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>; + clock-names = "apb_pclk"; + + arm,cti-v8-arch; + cpu = <&CPU2>; + arm,cs-dev-assoc = <&etm2>; + }; + + /* CTI - CPU-3 */ + cti@85b000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x85b000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>; + clock-names = "apb_pclk"; + + arm,cti-v8-arch; + cpu = <&CPU3>; + arm,cs-dev-assoc = <&etm3>; + }; + + venus: video-codec@1d00000 { compatible = "qcom,msm8916-venus"; reg = <0x01d00000 0xff000>;
On Mon, Aug 19, 2019 at 10:13:58PM +0100, Mike Leach wrote:
Adds system and CPU bound CTI definitions for Qualcom msm8916 platform (Dragonboard DB410C). System CTIs 2-11 are omitted as no information available at present.
Signed-off-by: Mike Leach mike.leach@linaro.org
arch/arm64/boot/dts/qcom/msm8916.dtsi | 85 +++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index 5ea9fb8f2f87..9589fc2cba22 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -8,6 +8,7 @@ #include <dt-bindings/reset/qcom,gcc-msm8916.h> #include <dt-bindings/clock/qcom,rpmcc.h> #include <dt-bindings/thermal/thermal.h> +#include <dt-bindings/arm/coresight-cti-dt.h> / { interrupt-parent = <&intc>; @@ -1357,7 +1358,7 @@ cpu = <&CPU3>; };
etm@85c000 {
etm0: etm@85c000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0x85c000 0x1000>;
@@ -1375,7 +1376,7 @@ }; };
etm@85d000 {
etm1: etm@85d000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0x85d000 0x1000>;
@@ -1393,7 +1394,7 @@ }; };
etm@85e000 {
etm2: etm@85e000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0x85e000 0x1000>;
@@ -1411,7 +1412,7 @@ }; };
etm@85f000 {
etm3: etm@85f000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0x85f000 0x1000>;
@@ -1429,6 +1430,82 @@ }; };
/* System CTIs */
/* CTI 0 - TMC connections */
cti@810000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x810000 0x1000>;
clocks = <&rpmcc RPM_QDSS_CLK>;
clock-names = "apb_pclk";
I have one question for the CTIs which are connected to TMC and TPIU devices:
Should This kind CTI have fixed trigger signals to connect between CTI and TMC/TPIU? If so, usually, can we get to know which trigger signals are connected and need to use the DT binding to define these trigger signals?
Or we just use the way in this patch without specifying any DT binding for trigger signals. Finally, the sysfs nodes allow to configure 0-7 triggers:
# cat /sys/bus/coresight/devices/cti_sys0/triggers0/in_signals 0-7 # cat /sys/bus/coresight/devices/cti_sys0/triggers0/in_types genio genio genio genio genio genio genio genio # cat /sys/bus/coresight/devices/cti_sys0/triggers0/out_signals 0-7 # cat /sys/bus/coresight/devices/cti_sys0/triggers0/out_types genio genio genio genio genio genio genio genio
};
/* CTI 1 - TPIU connections */
cti@811000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x811000 0x1000>;
clocks = <&rpmcc RPM_QDSS_CLK>;
clock-names = "apb_pclk";
};
/* CTIs 2-11 - no information - not instantiated */
/* Core CTIs; CTIs 12-15 */
/* CTI - CPU-0 */
cti@858000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x858000 0x1000>;
clocks = <&rpmcc RPM_QDSS_CLK>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&CPU0>;
arm,cs-dev-assoc = <&etm0>;
Redundant new line.
};
/* CTI - CPU-1 */
cti@859000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x859000 0x1000>;
clocks = <&rpmcc RPM_QDSS_CLK>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&CPU1>;
arm,cs-dev-assoc = <&etm1>;
Not sure if it's really redundant or not for 'cpu' node. Since we can see 'etm1' node also points to 'cpu' node, so actually we can get CPU related info by the path: arm,cs-dev-assoc -> etm1 -> cpu1.
By using this way, we can save one DT binding node? If you think this will cause much complexity for implementation, just ignore this comment.
};
/* CTI - CPU-2 */
cti@85a000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x85a000 0x1000>;
clocks = <&rpmcc RPM_QDSS_CLK>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&CPU2>;
arm,cs-dev-assoc = <&etm2>;
};
/* CTI - CPU-3 */
cti@85b000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x85b000 0x1000>;
clocks = <&rpmcc RPM_QDSS_CLK>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&CPU3>;
arm,cs-dev-assoc = <&etm3>;
};
Two new lines.
venus: video-codec@1d00000 { compatible = "qcom,msm8916-venus"; reg = <0x01d00000 0xff000>;
-- 2.17.1
CoreSight mailing list CoreSight@lists.linaro.org https://lists.linaro.org/mailman/listinfo/coresight
Hi Leo,
On Tue, 3 Sep 2019 at 09:19, Leo Yan leo.yan@linaro.org wrote:
On Mon, Aug 19, 2019 at 10:13:58PM +0100, Mike Leach wrote:
Adds system and CPU bound CTI definitions for Qualcom msm8916 platform (Dragonboard DB410C). System CTIs 2-11 are omitted as no information available at present.
Signed-off-by: Mike Leach mike.leach@linaro.org
arch/arm64/boot/dts/qcom/msm8916.dtsi | 85 +++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index 5ea9fb8f2f87..9589fc2cba22 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -8,6 +8,7 @@ #include <dt-bindings/reset/qcom,gcc-msm8916.h> #include <dt-bindings/clock/qcom,rpmcc.h> #include <dt-bindings/thermal/thermal.h> +#include <dt-bindings/arm/coresight-cti-dt.h>
/ { interrupt-parent = <&intc>; @@ -1357,7 +1358,7 @@ cpu = <&CPU3>; };
etm@85c000 {
etm0: etm@85c000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0x85c000 0x1000>;
@@ -1375,7 +1376,7 @@ }; };
etm@85d000 {
etm1: etm@85d000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0x85d000 0x1000>;
@@ -1393,7 +1394,7 @@ }; };
etm@85e000 {
etm2: etm@85e000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0x85e000 0x1000>;
@@ -1411,7 +1412,7 @@ }; };
etm@85f000 {
etm3: etm@85f000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0x85f000 0x1000>;
@@ -1429,6 +1430,82 @@ }; };
/* System CTIs */
/* CTI 0 - TMC connections */
cti@810000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x810000 0x1000>;
clocks = <&rpmcc RPM_QDSS_CLK>;
clock-names = "apb_pclk";
I have one question for the CTIs which are connected to TMC and TPIU devices:
Should This kind CTI have fixed trigger signals to connect between CTI and TMC/TPIU? If so, usually, can we get to know which trigger signals are connected and need to use the DT binding to define these trigger signals?
CTI signals between components are implementation dependent - determined by the hardware designer, except for the connections between the v8 PE, ETM and CTI that are required by the v8 architecture. So, other than v8 cores we need either documentation or to explore the connections using the integration control registers on the device.
For Juno I did this some time ago by mmap-ing the Coresight memory spaces into user space and reading and writing locations directly. That gave the connections you see in the .dtsi for Juno. Unfortunately using the integration control registers does not guarantee a usable system after their use, so this method cannot be used a boot / probe time.
If you look at the Juno .dtsi you will see that there are a number of connections specified between TPIU, ETR, ETF, STM and CTIs.. The types will be the same for other systems, we just do not know which signal on which CTI they might be connected to without further information.
Or we just use the way in this patch without specifying any DT binding for trigger signals. Finally, the sysfs nodes allow to configure 0-7 triggers:
# cat /sys/bus/coresight/devices/cti_sys0/triggers0/in_signals 0-7 # cat /sys/bus/coresight/devices/cti_sys0/triggers0/in_types genio genio genio genio genio genio genio genio # cat /sys/bus/coresight/devices/cti_sys0/triggers0/out_signals 0-7 # cat /sys/bus/coresight/devices/cti_sys0/triggers0/out_types genio genio genio genio genio genio genio genio
This is the default position - this allows specification of the CTI using the MAX_TRIGS specifcation in the hardware ID register. This does not mean that all these triggers are connected, but does allow access to the ones that are.
};
/* CTI 1 - TPIU connections */
cti@811000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x811000 0x1000>;
clocks = <&rpmcc RPM_QDSS_CLK>;
clock-names = "apb_pclk";
};
/* CTIs 2-11 - no information - not instantiated */
/* Core CTIs; CTIs 12-15 */
/* CTI - CPU-0 */
cti@858000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x858000 0x1000>;
clocks = <&rpmcc RPM_QDSS_CLK>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&CPU0>;
arm,cs-dev-assoc = <&etm0>;
Redundant new line.
};
/* CTI - CPU-1 */
cti@859000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x859000 0x1000>;
clocks = <&rpmcc RPM_QDSS_CLK>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&CPU1>;
arm,cs-dev-assoc = <&etm1>;
Not sure if it's really redundant or not for 'cpu' node. Since we can see 'etm1' node also points to 'cpu' node, so actually we can get CPU related info by the path: arm,cs-dev-assoc -> etm1 -> cpu1.
By using this way, we can save one DT binding node? If you think this will cause much complexity for implementation, just ignore this comment.
We cannot be sure at probe time if etm1 has been discovered. Therefore it is useful to collect all the information for this component here and compete the probing in one go.
};
/* CTI - CPU-2 */
cti@85a000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x85a000 0x1000>;
clocks = <&rpmcc RPM_QDSS_CLK>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&CPU2>;
arm,cs-dev-assoc = <&etm2>;
};
/* CTI - CPU-3 */
cti@85b000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x85b000 0x1000>;
clocks = <&rpmcc RPM_QDSS_CLK>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&CPU3>;
arm,cs-dev-assoc = <&etm3>;
};
Two new lines.
venus: video-codec@1d00000 { compatible = "qcom,msm8916-venus"; reg = <0x01d00000 0xff000>;
-- 2.17.1
CoreSight mailing list CoreSight@lists.linaro.org https://lists.linaro.org/mailman/listinfo/coresight
Will fix new lines
Thanks
Mike
Hi Mike,
On Tue, Sep 03, 2019 at 10:29:02AM +0100, Mike Leach wrote:
Hi Leo,
On Tue, 3 Sep 2019 at 09:19, Leo Yan leo.yan@linaro.org wrote:
On Mon, Aug 19, 2019 at 10:13:58PM +0100, Mike Leach wrote:
Adds system and CPU bound CTI definitions for Qualcom msm8916 platform (Dragonboard DB410C). System CTIs 2-11 are omitted as no information available at present.
Signed-off-by: Mike Leach mike.leach@linaro.org
arch/arm64/boot/dts/qcom/msm8916.dtsi | 85 +++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index 5ea9fb8f2f87..9589fc2cba22 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -8,6 +8,7 @@ #include <dt-bindings/reset/qcom,gcc-msm8916.h> #include <dt-bindings/clock/qcom,rpmcc.h> #include <dt-bindings/thermal/thermal.h> +#include <dt-bindings/arm/coresight-cti-dt.h>
/ { interrupt-parent = <&intc>; @@ -1357,7 +1358,7 @@ cpu = <&CPU3>; };
etm@85c000 {
etm0: etm@85c000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0x85c000 0x1000>;
@@ -1375,7 +1376,7 @@ }; };
etm@85d000 {
etm1: etm@85d000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0x85d000 0x1000>;
@@ -1393,7 +1394,7 @@ }; };
etm@85e000 {
etm2: etm@85e000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0x85e000 0x1000>;
@@ -1411,7 +1412,7 @@ }; };
etm@85f000 {
etm3: etm@85f000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0x85f000 0x1000>;
@@ -1429,6 +1430,82 @@ }; };
/* System CTIs */
/* CTI 0 - TMC connections */
cti@810000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x810000 0x1000>;
clocks = <&rpmcc RPM_QDSS_CLK>;
clock-names = "apb_pclk";
I have one question for the CTIs which are connected to TMC and TPIU devices:
Should This kind CTI have fixed trigger signals to connect between CTI and TMC/TPIU? If so, usually, can we get to know which trigger signals are connected and need to use the DT binding to define these trigger signals?
CTI signals between components are implementation dependent - determined by the hardware designer, except for the connections between the v8 PE, ETM and CTI that are required by the v8 architecture. So, other than v8 cores we need either documentation or to explore the connections using the integration control registers on the device.
For Juno I did this some time ago by mmap-ing the Coresight memory spaces into user space and reading and writing locations directly. That gave the connections you see in the .dtsi for Juno.
Thanks a lot for sharing this info. I just curious, how about to parse the integration control registers on DB410c and Hikey board?
I think it's valuable to use some tool to parse integration control registers (thus software engineers don't need to talk to silicon engineer and can get to know the connections).
Anyway, I think we could take this as low priority and firstly focus on upstreaming this patch set.
Unfortunately using the integration control registers does not guarantee a usable system after their use, so this method cannot be used a boot / probe time.
Okay, this is fine. I totally agree we can use simple method as the first step.
TBH, sorry I have no sense for this; "does not guarantee a usable system" will lead to what's result? Just the wrong configuration or some serious issue, like system hang?
If you look at the Juno .dtsi you will see that there are a number of connections specified between TPIU, ETR, ETF, STM and CTIs.. The types will be the same for other systems, we just do not know which signal on which CTI they might be connected to without further information.
[...]
};
/* CTI - CPU-1 */
cti@859000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x859000 0x1000>;
clocks = <&rpmcc RPM_QDSS_CLK>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&CPU1>;
arm,cs-dev-assoc = <&etm1>;
Not sure if it's really redundant or not for 'cpu' node. Since we can see 'etm1' node also points to 'cpu' node, so actually we can get CPU related info by the path: arm,cs-dev-assoc -> etm1 -> cpu1.
By using this way, we can save one DT binding node? If you think this will cause much complexity for implementation, just ignore this comment.
We cannot be sure at probe time if etm1 has been discovered. Therefore it is useful to collect all the information for this component here and compete the probing in one go.
From my understanding, here should have no dependency.
'etm1' node can be accessed by using phandle and retrieve its properies with 'of' related functions; it doesn't mean we must access 'etm1' node after the 'etm1' device has been probed.
Thanks, Leo Yan
[...]
Hi Leo,
On Thu, 5 Sep 2019 at 10:06, Leo Yan leo.yan@linaro.org wrote:
Hi Mike,
On Tue, Sep 03, 2019 at 10:29:02AM +0100, Mike Leach wrote:
Hi Leo,
On Tue, 3 Sep 2019 at 09:19, Leo Yan leo.yan@linaro.org wrote:
On Mon, Aug 19, 2019 at 10:13:58PM +0100, Mike Leach wrote:
Adds system and CPU bound CTI definitions for Qualcom msm8916 platform (Dragonboard DB410C). System CTIs 2-11 are omitted as no information available at present.
Signed-off-by: Mike Leach mike.leach@linaro.org
arch/arm64/boot/dts/qcom/msm8916.dtsi | 85 +++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index 5ea9fb8f2f87..9589fc2cba22 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -8,6 +8,7 @@ #include <dt-bindings/reset/qcom,gcc-msm8916.h> #include <dt-bindings/clock/qcom,rpmcc.h> #include <dt-bindings/thermal/thermal.h> +#include <dt-bindings/arm/coresight-cti-dt.h>
/ { interrupt-parent = <&intc>; @@ -1357,7 +1358,7 @@ cpu = <&CPU3>; };
etm@85c000 {
etm0: etm@85c000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0x85c000 0x1000>;
@@ -1375,7 +1376,7 @@ }; };
etm@85d000 {
etm1: etm@85d000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0x85d000 0x1000>;
@@ -1393,7 +1394,7 @@ }; };
etm@85e000 {
etm2: etm@85e000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0x85e000 0x1000>;
@@ -1411,7 +1412,7 @@ }; };
etm@85f000 {
etm3: etm@85f000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0x85f000 0x1000>;
@@ -1429,6 +1430,82 @@ }; };
/* System CTIs */
/* CTI 0 - TMC connections */
cti@810000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x810000 0x1000>;
clocks = <&rpmcc RPM_QDSS_CLK>;
clock-names = "apb_pclk";
I have one question for the CTIs which are connected to TMC and TPIU devices:
Should This kind CTI have fixed trigger signals to connect between CTI and TMC/TPIU? If so, usually, can we get to know which trigger signals are connected and need to use the DT binding to define these trigger signals?
CTI signals between components are implementation dependent - determined by the hardware designer, except for the connections between the v8 PE, ETM and CTI that are required by the v8 architecture. So, other than v8 cores we need either documentation or to explore the connections using the integration control registers on the device.
For Juno I did this some time ago by mmap-ing the Coresight memory spaces into user space and reading and writing locations directly. That gave the connections you see in the .dtsi for Juno.
Thanks a lot for sharing this info. I just curious, how about to parse the integration control registers on DB410c and Hikey board?
I think it's valuable to use some tool to parse integration control registers (thus software engineers don't need to talk to silicon engineer and can get to know the connections).
mmap would be the best method at present as the only the CTI driver has options to expose these registers at present.
There are issues with power here too -- Juno powers everything up but other boards may be trickier.
Anyway, I think we could take this as low priority and firstly focus on upstreaming this patch set.
Unfortunately using the integration control registers does not guarantee a usable system after their use, so this method cannot be used a boot / probe time.
Okay, this is fine. I totally agree we can use simple method as the first step.
TBH, sorry I have no sense for this; "does not guarantee a usable system" will lead to what's result? Just the wrong configuration or some serious issue, like system hang?
It could be either - the result is just not predictable.
If you look at the Juno .dtsi you will see that there are a number of connections specified between TPIU, ETR, ETF, STM and CTIs.. The types will be the same for other systems, we just do not know which signal on which CTI they might be connected to without further information.
[...]
};
/* CTI - CPU-1 */
cti@859000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x859000 0x1000>;
clocks = <&rpmcc RPM_QDSS_CLK>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&CPU1>;
arm,cs-dev-assoc = <&etm1>;
Not sure if it's really redundant or not for 'cpu' node. Since we can see 'etm1' node also points to 'cpu' node, so actually we can get CPU related info by the path: arm,cs-dev-assoc -> etm1 -> cpu1.
By using this way, we can save one DT binding node? If you think this will cause much complexity for implementation, just ignore this comment.
We cannot be sure at probe time if etm1 has been discovered. Therefore it is useful to collect all the information for this component here and compete the probing in one go.
From my understanding, here should have no dependency.
'etm1' node can be accessed by using phandle and retrieve its properies with 'of' related functions; it doesn't mean we must access 'etm1' node after the 'etm1' device has been probed.
Bear in mind that ETM is optional - we still need cpu.
Thanks, Leo Yan
[...]
regards
Mike
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
Add in CTI entries for Juno r0, r1 and r2 to device tree entries.
Signed-off-by: Mike Leach mike.leach@linaro.org --- arch/arm64/boot/dts/arm/juno-base.dtsi | 149 +++++++++++++++++++++- arch/arm64/boot/dts/arm/juno-cs-r1r2.dtsi | 31 ++++- arch/arm64/boot/dts/arm/juno-r1.dts | 25 ++++ arch/arm64/boot/dts/arm/juno-r2.dts | 25 ++++ arch/arm64/boot/dts/arm/juno.dts | 25 ++++ 5 files changed, 250 insertions(+), 5 deletions(-)
diff --git a/arch/arm64/boot/dts/arm/juno-base.dtsi b/arch/arm64/boot/dts/arm/juno-base.dtsi index 26a039a028b8..eb28ac340dd1 100644 --- a/arch/arm64/boot/dts/arm/juno-base.dtsi +++ b/arch/arm64/boot/dts/arm/juno-base.dtsi @@ -108,7 +108,7 @@ * The actual size is just 4K though 64K is reserved. Access to the * unmapped reserved region results in a DECERR response. */ - etf@20010000 { /* etf0 */ + etf_sys0: etf@20010000 { /* etf0 */ compatible = "arm,coresight-tmc", "arm,primecell"; reg = <0 0x20010000 0 0x1000>;
@@ -132,7 +132,7 @@ }; };
- tpiu@20030000 { + tpiu_sys: tpiu@20030000 { compatible = "arm,coresight-tpiu", "arm,primecell"; reg = <0 0x20030000 0 0x1000>;
@@ -185,7 +185,7 @@ }; };
- etr@20070000 { + etr_sys: etr@20070000 { compatible = "arm,coresight-tmc", "arm,primecell"; reg = <0 0x20070000 0 0x1000>; iommus = <&smmu_etr 0>; @@ -203,7 +203,7 @@ }; };
- stm@20100000 { + stm_sys: stm@20100000 { compatible = "arm,coresight-stm", "arm,primecell"; reg = <0 0x20100000 0 0x1000>, <0 0x28000000 0 0x1000000>; @@ -280,6 +280,18 @@ }; };
+ cti0: cti@22020000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0 0x22020000 0 0x1000>; + + clocks = <&soc_smc50mhz>; + clock-names = "apb_pclk"; + power-domains = <&scpi_devpd 0>; + + arm,cti-v8-arch; + arm,cs-dev-assoc = <&etm0>; + }; + funnel@220c0000 { /* cluster0 funnel */ compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; reg = <0 0x220c0000 0 0x1000>; @@ -340,6 +352,18 @@ }; };
+ cti1: cti@22120000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0 0x22120000 0 0x1000>; + + clocks = <&soc_smc50mhz>; + clock-names = "apb_pclk"; + power-domains = <&scpi_devpd 0>; + + arm,cti-v8-arch; + arm,cs-dev-assoc = <&etm1>; + }; + cpu_debug2: cpu-debug@23010000 { compatible = "arm,coresight-cpu-debug", "arm,primecell"; reg = <0x0 0x23010000 0x0 0x1000>; @@ -365,6 +389,18 @@ }; };
+ cti2: cti@23020000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0 0x23020000 0 0x1000>; + + clocks = <&soc_smc50mhz>; + clock-names = "apb_pclk"; + power-domains = <&scpi_devpd 0>; + + arm,cti-v8-arch; + arm,cs-dev-assoc = <&etm2>; + }; + funnel@230c0000 { /* cluster1 funnel */ compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; reg = <0 0x230c0000 0 0x1000>; @@ -437,6 +473,18 @@ }; };
+ cti3: cti@23120000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0 0x23120000 0 0x1000>; + + clocks = <&soc_smc50mhz>; + clock-names = "apb_pclk"; + power-domains = <&scpi_devpd 0>; + + arm,cti-v8-arch; + arm,cs-dev-assoc = <&etm3>; + }; + cpu_debug4: cpu-debug@23210000 { compatible = "arm,coresight-cpu-debug", "arm,primecell"; reg = <0x0 0x23210000 0x0 0x1000>; @@ -462,6 +510,18 @@ }; };
+ cti4: cti@23220000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0 0x23220000 0 0x1000>; + + clocks = <&soc_smc50mhz>; + clock-names = "apb_pclk"; + power-domains = <&scpi_devpd 0>; + + arm,cti-v8-arch; + arm,cs-dev-assoc = <&etm4>; + }; + cpu_debug5: cpu-debug@23310000 { compatible = "arm,coresight-cpu-debug", "arm,primecell"; reg = <0x0 0x23310000 0x0 0x1000>; @@ -487,6 +547,87 @@ }; };
+ cti5: cti@23320000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0 0x23320000 0 0x1000>; + + clocks = <&soc_smc50mhz>; + clock-names = "apb_pclk"; + power-domains = <&scpi_devpd 0>; + + arm,cti-v8-arch; + arm,cs-dev-assoc = <&etm5>; + }; + + + cti@20020000 { /* sys_cti_0 */ + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0 0x20020000 0 0x1000>; + + clocks = <&soc_smc50mhz>; + clock-names = "apb_pclk"; + power-domains = <&scpi_devpd 0>; + + trig-conns@0 { + arm,trig-in-sigs=<2 3>; + arm,trig-in-types=<SNK_FULL SNK_ACQCOMP>; + arm,trig-out-sigs=<0 1>; + arm,trig-out-types=<SNK_FLUSHIN SNK_TRIGIN>; + arm,cs-dev-assoc = <&etr_sys>; + }; + + trig-conns@1 { + arm,trig-in-sigs=<0 1>; + arm,trig-in-types=<SNK_FULL SNK_ACQCOMP>; + arm,trig-out-sigs=<7 6>; + arm,trig-out-types=<SNK_FLUSHIN SNK_TRIGIN>; + arm,cs-dev-assoc = <&etf_sys0>; + }; + + trig-conns@2 { + arm,trig-in-sigs=<4 5 6 7>; + arm,trig-in-types=<STM_TOUT_SPTE STM_TOUT_SW STM_TOUT_HETE STM_ASYNCOUT>; + arm,trig-out-sigs=<4 5>; + arm,trig-out-types=<STM_HWEVENT STM_HWEVENT>; + arm,cs-dev-assoc = <&stm_sys>; + }; + + trig-conns@3 { + arm,trig-out-sigs=<2 3>; + arm,trig-out-types=<SNK_FLUSHIN SNK_TRIGIN>; + arm,cs-dev-assoc = <&tpiu_sys>; + }; + }; + + cti@20110000 { /* sys_cti_1 */ + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0 0x20110000 0 0x1000>; + + clocks = <&soc_smc50mhz>; + clock-names = "apb_pclk"; + power-domains = <&scpi_devpd 0>; + + trig-conns@0 { + arm,trig-in-sigs=<0>; + arm,trig-in-types=<GEN_INTREQ>; + arm,trig-out-sigs=<0>; + arm,trig-out-types=<GEN_HALTREQ>; + arm,trig-conn-name = "sys_profiler"; + }; + + trig-conns@1 { + arm,trig-out-sigs=<2 3>; + arm,trig-out-types=<GEN_HALTREQ GEN_RESTARTREQ>; + arm,trig-conn-name = "watchdog"; + }; + + trig-conns@2 { + arm,trig-out-sigs=<1 6>; + arm,trig-out-types=<GEN_HALTREQ GEN_RESTARTREQ>; + arm,trig-conn-name = "g_counter"; + }; + }; + sram: sram@2e000000 { compatible = "arm,juno-sram-ns", "mmio-sram"; reg = <0x0 0x2e000000 0x0 0x8000>; diff --git a/arch/arm64/boot/dts/arm/juno-cs-r1r2.dtsi b/arch/arm64/boot/dts/arm/juno-cs-r1r2.dtsi index eda3d9e18af6..308f4eee8b29 100644 --- a/arch/arm64/boot/dts/arm/juno-cs-r1r2.dtsi +++ b/arch/arm64/boot/dts/arm/juno-cs-r1r2.dtsi @@ -23,7 +23,7 @@ }; };
- etf@20140000 { /* etf1 */ + etf_sys1: etf@20140000 { /* etf1 */ compatible = "arm,coresight-tmc", "arm,primecell"; reg = <0 0x20140000 0 0x1000>;
@@ -82,4 +82,33 @@
}; }; + + cti@20160000 { /* sys_cti_2 */ + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0 0x20160000 0 0x1000>; + + clocks = <&soc_smc50mhz>; + clock-names = "apb_pclk"; + power-domains = <&scpi_devpd 0>; + + trig-conns@0 { + arm,trig-in-sigs=<0 1>; + arm,trig-in-types=<SNK_FULL SNK_ACQCOMP>; + arm,trig-out-sigs=<0 1>; + arm,trig-out-types=<SNK_FLUSHIN SNK_TRIGIN>; + arm,cs-dev-assoc = <&etf_sys1>; + }; + + trig-conns@1 { + arm,trig-in-sigs=<2 3 4>; + arm,trig-in-types=<ELA_DBGREQ ELA_TSTART ELA_TSTOP>; + arm,trig-conn-name = "ela_clus_0"; + }; + + trig-conns@2 { + arm,trig-in-sigs=<5 6 7>; + arm,trig-in-types=<ELA_DBGREQ ELA_TSTART ELA_TSTOP>; + arm,trig-conn-name = "ela_clus_1"; + }; + }; }; diff --git a/arch/arm64/boot/dts/arm/juno-r1.dts b/arch/arm64/boot/dts/arm/juno-r1.dts index 5f290090b0cf..02aa51eb311d 100644 --- a/arch/arm64/boot/dts/arm/juno-r1.dts +++ b/arch/arm64/boot/dts/arm/juno-r1.dts @@ -9,6 +9,7 @@ /dts-v1/;
#include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/arm/coresight-cti-dt.h> #include "juno-base.dtsi" #include "juno-cs-r1r2.dtsi"
@@ -309,3 +310,27 @@ &cpu_debug5 { cpu = <&A53_3>; }; + +&cti0 { + cpu = <&A57_0>; +}; + +&cti1 { + cpu = <&A57_1>; +}; + +&cti2 { + cpu = <&A53_0>; +}; + +&cti3 { + cpu = <&A53_1>; +}; + +&cti4 { + cpu = <&A53_2>; +}; + +&cti5 { + cpu = <&A53_3>; +}; diff --git a/arch/arm64/boot/dts/arm/juno-r2.dts b/arch/arm64/boot/dts/arm/juno-r2.dts index 305300dd521c..75bb27c2d4dc 100644 --- a/arch/arm64/boot/dts/arm/juno-r2.dts +++ b/arch/arm64/boot/dts/arm/juno-r2.dts @@ -9,6 +9,7 @@ /dts-v1/;
#include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/arm/coresight-cti-dt.h> #include "juno-base.dtsi" #include "juno-cs-r1r2.dtsi"
@@ -315,3 +316,27 @@ &cpu_debug5 { cpu = <&A53_3>; }; + +&cti0 { + cpu = <&A72_0>; +}; + +&cti1 { + cpu = <&A72_1>; +}; + +&cti2 { + cpu = <&A53_0>; +}; + +&cti3 { + cpu = <&A53_1>; +}; + +&cti4 { + cpu = <&A53_2>; +}; + +&cti5 { + cpu = <&A53_3>; +}; diff --git a/arch/arm64/boot/dts/arm/juno.dts b/arch/arm64/boot/dts/arm/juno.dts index f00cffbd032c..dbc22e70b62c 100644 --- a/arch/arm64/boot/dts/arm/juno.dts +++ b/arch/arm64/boot/dts/arm/juno.dts @@ -9,6 +9,7 @@ /dts-v1/;
#include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/arm/coresight-cti-dt.h> #include "juno-base.dtsi"
/ { @@ -295,3 +296,27 @@ &cpu_debug5 { cpu = <&A53_3>; }; + +&cti0 { + cpu = <&A57_0>; +}; + +&cti1 { + cpu = <&A57_1>; +}; + +&cti2 { + cpu = <&A53_0>; +}; + +&cti3 { + cpu = <&A53_1>; +}; + +&cti4 { + cpu = <&A53_2>; +}; + +&cti5 { + cpu = <&A53_3>; +};
Add section in coresight.txt explaining operation and use of CTI devices in CoreSight.
Signed-off-by: Mike Leach mike.leach@linaro.org --- Documentation/trace/coresight-ect.txt | 164 ++++++++++++++++++++++++++ Documentation/trace/coresight.txt | 7 ++ MAINTAINERS | 1 + 3 files changed, 172 insertions(+) create mode 100644 Documentation/trace/coresight-ect.txt
diff --git a/Documentation/trace/coresight-ect.txt b/Documentation/trace/coresight-ect.txt new file mode 100644 index 000000000000..298123963dd2 --- /dev/null +++ b/Documentation/trace/coresight-ect.txt @@ -0,0 +1,164 @@ +CoreSight Embedded Cross Trigger (CTI & CTM). +--------------------------------------------- + +The CoreSight Cross Trigger Interface (CTI) is a hardware device that takes +individual input and output hardware signals known as triggers to and from +devices and interconnects them via the Cross Trigger Matrix (CTM) to other +devices via numbered channels, in order to propagate events between devices. + +e.g. + + 0000000 in_trigs ::::::: + 0 C 0----------->: : +======>(other CTI channel IO) + 0 P 0<-----------: : v + 0 U 0 out_trigs : : Channels ***** ::::::: + 0000000 : CTI :<=========>*CTM*<====>: CTI :---+ + ####### in_trigs : : (id 0-3) ***** ::::::: v + # ETM #----------->: : ^ ####### + # #<-----------: : +---# ETR # + ####### out_trigs ::::::: ####### + +The CTI driver enables the programming of the CTI to attach triggers to +channels. When an input trigger becomes active, the attached channel will +become active. Any output trigger attached to that channel will also +become active. The active channel is propagated to other CTIs via the CTM, +activiating connected output triggers there, unless filtered by the CTI +channel gate. + +It is also possible to activate a channel using system software directly +programming registers in the CTI. + +The CTIs are registered by the system to be associated with CPUs and/or other +CoreSight devices on the trace data path. When these devices are enabled the +attached CTIs will also be enabled. By default/on power up the CTIs have +no programmed trigger/channel attachments, so will not affect the system +until explicitly programmed. + +The hardware trigger connections between CTIs and devices is implementation +defined, unless the CPU/ETM combination is a v8 architecture, in which case +the connections have an architecturally defined standard layout. + +The hardware trigger signals can also be connected to non-CoreSight devices +(e.g. UART), or be propagated off chip as hardware IO lines. + +All the CTI devices are associated with a CTM. On many systems there will be a +single effective CTM (one CTM, or multiple CTMs all interconnected), but it is +possible that systems can have nets of CTIs+CTM that are not interconnected by +a CTM to each other. On these systems a CTM index is declared to associate +CTI devices that are interconnected via a given CTM. + +The CTI devices appear on the existing CoreSight bus alongside the other +CoreSight devices. + +>$ ls /sys/bus/coresight/devices +cti_cpu0 cti_cpu2 cti_sys0 etm0 etm2 funnel0 replicator0 tmc_etr0 +cti_cpu1 cti_cpu3 cti_sys1 etm1 etm3 funnel1 tmc_etf0 tpiu0 + +The cti_cpu<N> named CTIs are associated with a CPU, and any ETM used by that +core. the cti_sys<N> CTIs are general system infrastructure CTIs that can be +associated with other CoreSight devices, or other system hardware capable of +generating or using trigger signals. + +>$ ls /sys/bus/coresight/devices/etm0/cti_cpu0 +channels connections ctmid enable mgmt power regs subsystem triggers0 +triggers1 uevent + +Key file items are + * enable: enables/disables the CTI. + * ctmid : associated CTM - only relevant if system has multiple CTI+CTM + clusters that are not interconnected. + +Sub-directories:- + *triggers<N>: contains list of triggers for an individual connection + *connections: contains general connection information for the CTI plus + sysfs links to other registered CoreSight components that connect to + this CTI. + *channels: Contains the channel API - CTI main programming interface. + *regs: Gives access to the raw programmable CTI regs. + *mgmt: the standard CoreSight management registers. + +** Connections: This contains a list of general data describing the devices +connected to this CTI, and links to other CoreSight devices. + +>$ ls -l ./cti_cpu0/connections/ +nr_cons trigout_filtered etm0 -> ../../../85c000.etm/etm0 + + * nr_cons - total number of connections - triggers<N> directories. + * trigout_filtered - trigger out signals that are prevented from being + set if filtering is enabled. Prevents accidental edbgreq signals + stopping a core. + * etm0 - link showing connected CoreSight device - this will be named + according to the connected device. Multiple links will appear when a + CTI is connected to multiple CoreSight devices + +** triggers<N>: Individual trigger connections. + +Each triggers directory has a set of parameters describing the triggers for +the connection. + * name : name of connection + * in_signals : input trigger signal indexes used in this connection. + * in_types : functional types for in signals. + * out_signals : output trigger signals for this connection. + * out_types : functional types for out signals. + +e.g. +>$ ls ./cti_cpu0/triggers0/ +in_signals in_types name out_signals out_types +>$ cat ./cti_cpu0/triggers0/name +cpu0 +>$ cat ./cti_cpu0/triggers0/out_signals +0-2 +>$ cat ./cti_cpu0/triggers0/out_types +pe_edbgreq pe_dbgrestart pe_ctiirq +>$ cat ./cti_cpu0/triggers0/in_signals +0-1 +>$ cat ./cti_cpu0/triggers0/in_types +pe_dbgtrigger pe_pmuirq + +If a connection has zero signals in either the in or out triggers then those +parameters will be omitted. + +** Channels API : This provides an easy way to attach triggers to channels, +without needing the multiple register operations that are required if +manipluating the 'regs' sub-dir elements directly. + +>$ ls ./cti_sys0/channels/ +chan_clear gate_disable list_gate_enable show_chan_sel trigin_attach +chan_pulse gate_enable list_inuse show_chan_xtrigs trigin_detach +chan_set list_free reset_xtrigs trig_filter_enable trigout_attach +trigout_detach + +Most access to these elements take the form: +echo <chan> [<trigger>] > /<device_path>/<operation> +where the optional <trigger> is only needed for trigXX_at|detach operations. + +e.g. +>$ echo 0 1 > ./cti_sys0/channels/trigin_attach +attach trig_in(1) to channel(0). +echo 0 > ./cti_sys0/channels/chan_set +activate channel(0) + + *gate_enable, gate_disable operations set the CTI gate to propagate + (enable) to other devices. These operation can take a channel number + or 'all' to operate on all channels. CTI gate is enabled by default + at power up. + *list_gate_enable: show the current channels enabled through the gate. + *list_inuse: show the current channels attached to any signal + *list_free: show channels with no attached signals. + *show_chan_sel: select the channel for the show_chan_xtrigs operation. + *show_chan_xtrigs: show the cross triggers programmed for the selected + channel. + +.../cti_sys0/channels# echo 0 1 > trigin_attach +.../cti_sys0/channels# cat list_free +1 2 3 +.../cti_sys0/channels# cat list_inuse +0 +.../cti_sys0/channels# echo 0 > show_chan_sel +.../cti_sys0/channels# cat show_chan_xtrigs +IN: 1 OUT: + + *trig_filter_enable: defaults to enabled, disable to allow potentially + dangerous output signals to be set. + *reset_xtrigs: clear all channel / trigger programming - reset device + hardware to default state. diff --git a/Documentation/trace/coresight.txt b/Documentation/trace/coresight.txt index b027d61b27a6..f37d927a368c 100644 --- a/Documentation/trace/coresight.txt +++ b/Documentation/trace/coresight.txt @@ -477,6 +477,13 @@ root@genericarmv8:~#
Details on how to use the generic STM API can be found here [2].
+The CTI Module +-------------- + +A separate documentation file is provided to explain the use of CTI devices. +(Documentation/trace/coresight-ect.txt) + + [1]. Documentation/ABI/testing/sysfs-bus-coresight-devices-stm [2]. Documentation/trace/stm.rst [3]. https://github.com/Linaro/perf-opencsd diff --git a/MAINTAINERS b/MAINTAINERS index a81f3bd8340a..45cfe624cb8c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1585,6 +1585,7 @@ F: drivers/hwtracing/coresight/* F: include/dt-bindings/arm/coresight-cti-dt.h F: Documentation/trace/coresight.txt F: Documentation/trace/coresight-cpu-debug.txt +F: Documentation/trace/coresight-ect.txt F: Documentation/devicetree/bindings/arm/coresight.txt F: Documentation/devicetree/bindings/arm/coresight-cpu-debug.txt F: Documentation/devicetree/bindings/arm/coresight-ect-cti.txt
On Mon, Aug 19, 2019 at 10:14:00PM +0100, Mike Leach wrote:
Add section in coresight.txt explaining operation and use of CTI devices in CoreSight.
Signed-off-by: Mike Leach mike.leach@linaro.org
Documentation/trace/coresight-ect.txt | 164 ++++++++++++++++++++++++++ Documentation/trace/coresight.txt | 7 ++ MAINTAINERS | 1 + 3 files changed, 172 insertions(+) create mode 100644 Documentation/trace/coresight-ect.txt
diff --git a/Documentation/trace/coresight-ect.txt b/Documentation/trace/coresight-ect.txt new file mode 100644 index 000000000000..298123963dd2 --- /dev/null +++ b/Documentation/trace/coresight-ect.txt @@ -0,0 +1,164 @@ +CoreSight Embedded Cross Trigger (CTI & CTM). +---------------------------------------------
+The CoreSight Cross Trigger Interface (CTI) is a hardware device that takes +individual input and output hardware signals known as triggers to and from +devices and interconnects them via the Cross Trigger Matrix (CTM) to other +devices via numbered channels, in order to propagate events between devices.
+e.g.
- 0000000 in_trigs :::::::
- 0 C 0----------->: : +======>(other CTI channel IO)
- 0 P 0<-----------: : v
- 0 U 0 out_trigs : : Channels ***** :::::::
- 0000000 : CTI :<=========>*CTM*<====>: CTI :---+
- ####### in_trigs : : (id 0-3) ***** ::::::: v
- # ETM #----------->: : ^ #######
- # #<-----------: : +---# ETR #
- ####### out_trigs ::::::: #######
+The CTI driver enables the programming of the CTI to attach triggers to +channels. When an input trigger becomes active, the attached channel will +become active. Any output trigger attached to that channel will also +become active. The active channel is propagated to other CTIs via the CTM, +activiating connected output triggers there, unless filtered by the CTI +channel gate.
+It is also possible to activate a channel using system software directly +programming registers in the CTI.
+The CTIs are registered by the system to be associated with CPUs and/or other +CoreSight devices on the trace data path. When these devices are enabled the +attached CTIs will also be enabled. By default/on power up the CTIs have +no programmed trigger/channel attachments, so will not affect the system +until explicitly programmed.
+The hardware trigger connections between CTIs and devices is implementation +defined, unless the CPU/ETM combination is a v8 architecture, in which case +the connections have an architecturally defined standard layout.
+The hardware trigger signals can also be connected to non-CoreSight devices +(e.g. UART), or be propagated off chip as hardware IO lines.
+All the CTI devices are associated with a CTM. On many systems there will be a +single effective CTM (one CTM, or multiple CTMs all interconnected), but it is +possible that systems can have nets of CTIs+CTM that are not interconnected by +a CTM to each other. On these systems a CTM index is declared to associate +CTI devices that are interconnected via a given CTM.
+The CTI devices appear on the existing CoreSight bus alongside the other +CoreSight devices.
+>$ ls /sys/bus/coresight/devices +cti_cpu0 cti_cpu2 cti_sys0 etm0 etm2 funnel0 replicator0 tmc_etr0 +cti_cpu1 cti_cpu3 cti_sys1 etm1 etm3 funnel1 tmc_etf0 tpiu0
+The cti_cpu<N> named CTIs are associated with a CPU, and any ETM used by that +core. the cti_sys<N> CTIs are general system infrastructure CTIs that can be +associated with other CoreSight devices, or other system hardware capable of +generating or using trigger signals.
+>$ ls /sys/bus/coresight/devices/etm0/cti_cpu0 +channels connections ctmid enable mgmt power regs subsystem triggers0 +triggers1 uevent
+Key file items are
- enable: enables/disables the CTI.
- ctmid : associated CTM - only relevant if system has multiple CTI+CTM
- clusters that are not interconnected.
+Sub-directories:-
- *triggers<N>: contains list of triggers for an individual connection
- *connections: contains general connection information for the CTI plus
- sysfs links to other registered CoreSight components that connect to
- this CTI.
- *channels: Contains the channel API - CTI main programming interface.
- *regs: Gives access to the raw programmable CTI regs.
- *mgmt: the standard CoreSight management registers.
+** Connections: This contains a list of general data describing the devices +connected to this CTI, and links to other CoreSight devices.
+>$ ls -l ./cti_cpu0/connections/ +nr_cons trigout_filtered etm0 -> ../../../85c000.etm/etm0
* nr_cons - total number of connections - triggers<N> directories.
* trigout_filtered - trigger out signals that are prevented from being
set if filtering is enabled. Prevents accidental edbgreq signals
stopping a core.
* etm0 - link showing connected CoreSight device - this will be named
according to the connected device. Multiple links will appear when a
CTI is connected to multiple CoreSight devices
Seems to me, the nodes 'inen', 'inout_sel' and 'outen' under /sys/bus/coresight/devices/cti_X/regs/ should be moved to 'connections' folder. Since we can use these nodes to enable the connections between channel and triggers.
+** triggers<N>: Individual trigger connections.
+Each triggers directory has a set of parameters describing the triggers for +the connection.
- name : name of connection
- in_signals : input trigger signal indexes used in this connection.
- in_types : functional types for in signals.
- out_signals : output trigger signals for this connection.
- out_types : functional types for out signals.
+e.g. +>$ ls ./cti_cpu0/triggers0/ +in_signals in_types name out_signals out_types +>$ cat ./cti_cpu0/triggers0/name +cpu0 +>$ cat ./cti_cpu0/triggers0/out_signals +0-2 +>$ cat ./cti_cpu0/triggers0/out_types +pe_edbgreq pe_dbgrestart pe_ctiirq +>$ cat ./cti_cpu0/triggers0/in_signals +0-1 +>$ cat ./cti_cpu0/triggers0/in_types +pe_dbgtrigger pe_pmuirq
+If a connection has zero signals in either the in or out triggers then those +parameters will be omitted.
+** Channels API : This provides an easy way to attach triggers to channels, +without needing the multiple register operations that are required if +manipluating the 'regs' sub-dir elements directly.
+>$ ls ./cti_sys0/channels/ +chan_clear gate_disable list_gate_enable show_chan_sel trigin_attach +chan_pulse gate_enable list_inuse show_chan_xtrigs trigin_detach +chan_set list_free reset_xtrigs trig_filter_enable trigout_attach +trigout_detach
Several comments for channels.
The 'chan_clear'/'chan_pulse'/'chan_set' nodes are easily to introduce confusion when I use them. Other nodes will directly use the input values, but these three nodes will take the input value as bit offset (e.g. if echo '0' > chan_set, actually it will set value (1 << 0)). So maybe we can use more directive naming to reflect this? E.g. chan_idx_{set|clear|pulse}.
'list_free', 'list_gate_enable' and 'list_inuse' are not very clear for the meaning of "list". IMHO, "chans" might be more friendly for users than "list". So finally we can get 'chans_free', 'chans_gate_enable', 'chans_inuse'.
Change 'show_chan_sel' to 'chan_sel'? This node is RW but not read-only property. The naming 'show_chan_sel' gives impression like a RO node.
+Most access to these elements take the form: +echo <chan> [<trigger>] > /<device_path>/<operation> +where the optional <trigger> is only needed for trigXX_at|detach operations.
+e.g. +>$ echo 0 1 > ./cti_sys0/channels/trigin_attach +attach trig_in(1) to channel(0). +echo 0 > ./cti_sys0/channels/chan_set +activate channel(0)
*gate_enable, gate_disable operations set the CTI gate to propagate
(enable) to other devices. These operation can take a channel number
or 'all' to operate on all channels. CTI gate is enabled by default
at power up.
*list_gate_enable: show the current channels enabled through the gate.
*list_inuse: show the current channels attached to any signal
*list_free: show channels with no attached signals.
*show_chan_sel: select the channel for the show_chan_xtrigs operation.
*show_chan_xtrigs: show the cross triggers programmed for the selected
channel.
+.../cti_sys0/channels# echo 0 1 > trigin_attach +.../cti_sys0/channels# cat list_free +1 2 3 +.../cti_sys0/channels# cat list_inuse +0 +.../cti_sys0/channels# echo 0 > show_chan_sel +.../cti_sys0/channels# cat show_chan_xtrigs +IN: 1 OUT:
- *trig_filter_enable: defaults to enabled, disable to allow potentially
- dangerous output signals to be set.
- *reset_xtrigs: clear all channel / trigger programming - reset device
- hardware to default state.
Suggest we can give a more complete example, e.g. we can use below steps to create connection between channel and triggers, and finally we can readout status register for triggering (below is an example I tested to send event from channel 0 to trigger 4, and finally we can read out the triggerout status to show the signal is asserted):
.../cti_cpu0# echo 1 > enable .../cti_cpu0/channels# echo 0 4 > trigout_attach .../cti_sys0/channels# echo 0 > show_chan_sel .../cti_cpu0/channels# cat show_chan_xtrigs IN: OUT: 4 .../cti_cpu0/channels# cat list_inuse 0 .../cti_cpu0/regs# echo 4 > inout_sel .../cti_cpu0/regs# echo 1 > outen .../cti_cpu0/channels# echo 0 > chan_set .../cti_cpu0/regs# cat trigoutstatus 0x10
Thanks, Leo Yan
diff --git a/Documentation/trace/coresight.txt b/Documentation/trace/coresight.txt index b027d61b27a6..f37d927a368c 100644 --- a/Documentation/trace/coresight.txt +++ b/Documentation/trace/coresight.txt @@ -477,6 +477,13 @@ root@genericarmv8:~# Details on how to use the generic STM API can be found here [2]. +The CTI Module +--------------
+A separate documentation file is provided to explain the use of CTI devices. +(Documentation/trace/coresight-ect.txt)
[1]. Documentation/ABI/testing/sysfs-bus-coresight-devices-stm [2]. Documentation/trace/stm.rst [3]. https://github.com/Linaro/perf-opencsd diff --git a/MAINTAINERS b/MAINTAINERS index a81f3bd8340a..45cfe624cb8c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1585,6 +1585,7 @@ F: drivers/hwtracing/coresight/* F: include/dt-bindings/arm/coresight-cti-dt.h F: Documentation/trace/coresight.txt F: Documentation/trace/coresight-cpu-debug.txt +F: Documentation/trace/coresight-ect.txt F: Documentation/devicetree/bindings/arm/coresight.txt F: Documentation/devicetree/bindings/arm/coresight-cpu-debug.txt F: Documentation/devicetree/bindings/arm/coresight-ect-cti.txt -- 2.17.1
CoreSight mailing list CoreSight@lists.linaro.org https://lists.linaro.org/mailman/listinfo/coresight
Hi Leo,
On Mon, 2 Sep 2019 at 14:26, Leo Yan leo.yan@linaro.org wrote:
On Mon, Aug 19, 2019 at 10:14:00PM +0100, Mike Leach wrote:
Add section in coresight.txt explaining operation and use of CTI devices in CoreSight.
Signed-off-by: Mike Leach mike.leach@linaro.org
Documentation/trace/coresight-ect.txt | 164 ++++++++++++++++++++++++++ Documentation/trace/coresight.txt | 7 ++ MAINTAINERS | 1 + 3 files changed, 172 insertions(+) create mode 100644 Documentation/trace/coresight-ect.txt
diff --git a/Documentation/trace/coresight-ect.txt
b/Documentation/trace/coresight-ect.txt
new file mode 100644 index 000000000000..298123963dd2 --- /dev/null +++ b/Documentation/trace/coresight-ect.txt @@ -0,0 +1,164 @@ +CoreSight Embedded Cross Trigger (CTI & CTM). +---------------------------------------------
+The CoreSight Cross Trigger Interface (CTI) is a hardware device that
takes
+individual input and output hardware signals known as triggers to and
from
+devices and interconnects them via the Cross Trigger Matrix (CTM) to
other
+devices via numbered channels, in order to propagate events between
devices.
+e.g.
- 0000000 in_trigs :::::::
- 0 C 0----------->: : +======>(other CTI channel IO)
- 0 P 0<-----------: : v
- 0 U 0 out_trigs : : Channels ***** :::::::
- 0000000 : CTI :<=========>*CTM*<====>: CTI :---+
- ####### in_trigs : : (id 0-3) ***** ::::::: v
- # ETM #----------->: : ^ #######
- # #<-----------: : +---# ETR #
- ####### out_trigs ::::::: #######
+The CTI driver enables the programming of the CTI to attach triggers to +channels. When an input trigger becomes active, the attached channel
will
+become active. Any output trigger attached to that channel will also +become active. The active channel is propagated to other CTIs via the
CTM,
+activiating connected output triggers there, unless filtered by the CTI +channel gate.
+It is also possible to activate a channel using system software
directly
+programming registers in the CTI.
+The CTIs are registered by the system to be associated with CPUs
and/or other
+CoreSight devices on the trace data path. When these devices are
enabled the
+attached CTIs will also be enabled. By default/on power up the CTIs
have
+no programmed trigger/channel attachments, so will not affect the
system
+until explicitly programmed.
+The hardware trigger connections between CTIs and devices is
implementation
+defined, unless the CPU/ETM combination is a v8 architecture, in which
case
+the connections have an architecturally defined standard layout.
+The hardware trigger signals can also be connected to non-CoreSight
devices
+(e.g. UART), or be propagated off chip as hardware IO lines.
+All the CTI devices are associated with a CTM. On many systems there
will be a
+single effective CTM (one CTM, or multiple CTMs all interconnected),
but it is
+possible that systems can have nets of CTIs+CTM that are not
interconnected by
+a CTM to each other. On these systems a CTM index is declared to
associate
+CTI devices that are interconnected via a given CTM.
+The CTI devices appear on the existing CoreSight bus alongside the
other
+CoreSight devices.
+>$ ls /sys/bus/coresight/devices +cti_cpu0 cti_cpu2 cti_sys0 etm0 etm2 funnel0 replicator0
tmc_etr0
+cti_cpu1 cti_cpu3 cti_sys1 etm1 etm3 funnel1 tmc_etf0 tpiu0
+The cti_cpu<N> named CTIs are associated with a CPU, and any ETM used
by that
+core. the cti_sys<N> CTIs are general system infrastructure CTIs that
can be
+associated with other CoreSight devices, or other system hardware
capable of
+generating or using trigger signals.
+>$ ls /sys/bus/coresight/devices/etm0/cti_cpu0 +channels connections ctmid enable mgmt power regs subsystem
triggers0
+triggers1 uevent
+Key file items are
* enable: enables/disables the CTI.
* ctmid : associated CTM - only relevant if system has multiple
CTI+CTM
clusters that are not interconnected.
+Sub-directories:-
*triggers<N>: contains list of triggers for an individual
connection
*connections: contains general connection information for the CTI
plus
sysfs links to other registered CoreSight components that connect
to
this CTI.
*channels: Contains the channel API - CTI main programming
interface.
*regs: Gives access to the raw programmable CTI regs.
*mgmt: the standard CoreSight management registers.
+** Connections: This contains a list of general data describing the
devices
+connected to this CTI, and links to other CoreSight devices.
+>$ ls -l ./cti_cpu0/connections/ +nr_cons trigout_filtered etm0 -> ../../../85c000.etm/etm0
* nr_cons - total number of connections - triggers<N>
directories.
* trigout_filtered - trigger out signals that are prevented from
being
set if filtering is enabled. Prevents accidental edbgreq signals
stopping a core.
* etm0 - link showing connected CoreSight device - this will be
named
according to the connected device. Multiple links will appear
when a
CTI is connected to multiple CoreSight devices
Seems to me, the nodes 'inen', 'inout_sel' and 'outen' under /sys/bus/coresight/devices/cti_X/regs/ should be moved to 'connections' folder. Since we can use these nodes to enable the connections between channel and triggers.
These are deliberately in the /regs sub-dir as they directly r/w registers rather than provide a higher level API. /connections is used to describe the fixed hardware links between components, not the transient links programmed up using the /regs or /channels API.
+** triggers<N>: Individual trigger connections.
+Each triggers directory has a set of parameters describing the
triggers for
+the connection.
* name : name of connection
* in_signals : input trigger signal indexes used in this
connection.
* in_types : functional types for in signals.
* out_signals : output trigger signals for this connection.
* out_types : functional types for out signals.
+e.g. +>$ ls ./cti_cpu0/triggers0/ +in_signals in_types name out_signals out_types +>$ cat ./cti_cpu0/triggers0/name +cpu0 +>$ cat ./cti_cpu0/triggers0/out_signals +0-2 +>$ cat ./cti_cpu0/triggers0/out_types +pe_edbgreq pe_dbgrestart pe_ctiirq +>$ cat ./cti_cpu0/triggers0/in_signals +0-1 +>$ cat ./cti_cpu0/triggers0/in_types +pe_dbgtrigger pe_pmuirq
+If a connection has zero signals in either the in or out triggers then
those
+parameters will be omitted.
+** Channels API : This provides an easy way to attach triggers to
channels,
+without needing the multiple register operations that are required if +manipluating the 'regs' sub-dir elements directly.
+>$ ls ./cti_sys0/channels/ +chan_clear gate_disable list_gate_enable show_chan_sel
trigin_attach
+chan_pulse gate_enable list_inuse show_chan_xtrigs
trigin_detach
+chan_set list_free reset_xtrigs trig_filter_enable
trigout_attach
+trigout_detach
Several comments for channels.
The 'chan_clear'/'chan_pulse'/'chan_set' nodes are easily to introduce confusion when I use them. Other nodes will directly use the input values, but these three nodes will take the input value as bit offset (e.g. if echo '0' > chan_set, actually it will set value (1 << 0)). So maybe we can use more directive naming to reflect this? E.g. chan_idx_{set|clear|pulse}.
OK - all the nodes in /channels use a <chan_idx> <trgger_idx> command format, or just <chan_idx> for operations that only affect a channel. This is consistent throuhout the API.
e,g, echo 0 1 > trigin_attach attaches signal input idx 1 to channel 0.
These will always translate the indexes to appropriate register writes - selecting the register and shifting bits as required. This means that the user does not need to know the bit positions for channels / indexes.
'list_free', 'list_gate_enable' and 'list_inuse' are not very clear for the meaning of "list". IMHO, "chans" might be more friendly for users than "list". So finally we can get 'chans_free', 'chans_gate_enable', 'chans_inuse'.
This seems reasonable. I think I might make chan_gate_enable rw - read will list enabled channels, and drop the list_ variant completely.
Change 'show_chan_sel' to 'chan_sel'? This node is RW but not read-only property. The naming 'show_chan_sel' gives impression like a RO node.
My concern with chan_sel is that users will assume this applies to all operations, not just the show xtrigs. Perhaps chan_xtrigs_sel / chan_xtrigs_show.
+Most access to these elements take the form: +echo <chan> [<trigger>] > /<device_path>/<operation> +where the optional <trigger> is only needed for trigXX_at|detach
operations.
+e.g. +>$ echo 0 1 > ./cti_sys0/channels/trigin_attach +attach trig_in(1) to channel(0). +echo 0 > ./cti_sys0/channels/chan_set +activate channel(0)
*gate_enable, gate_disable operations set the CTI gate to
propagate
(enable) to other devices. These operation can take a channel
number
or 'all' to operate on all channels. CTI gate is enabled by
default
at power up.
*list_gate_enable: show the current channels enabled through the
gate.
*list_inuse: show the current channels attached to any signal
*list_free: show channels with no attached signals.
*show_chan_sel: select the channel for the show_chan_xtrigs
operation.
*show_chan_xtrigs: show the cross triggers programmed for the
selected
channel.
+.../cti_sys0/channels# echo 0 1 > trigin_attach +.../cti_sys0/channels# cat list_free +1 2 3 +.../cti_sys0/channels# cat list_inuse +0 +.../cti_sys0/channels# echo 0 > show_chan_sel +.../cti_sys0/channels# cat show_chan_xtrigs +IN: 1 OUT:
*trig_filter_enable: defaults to enabled, disable to allow
potentially
dangerous output signals to be set.
*reset_xtrigs: clear all channel / trigger programming - reset
device
hardware to default state.
Suggest we can give a more complete example, e.g. we can use below steps to create connection between channel and triggers, and finally we can readout status register for triggering (below is an example I tested to send event from channel 0 to trigger 4, and finally we can read out the triggerout status to show the signal is asserted):
I’ll add a larger example.
Thanks and Regards
Mike
.../cti_cpu0# echo 1 > enable .../cti_cpu0/channels# echo 0 4 > trigout_attach .../cti_sys0/channels# echo 0 > show_chan_sel .../cti_cpu0/channels# cat show_chan_xtrigs IN: OUT: 4 .../cti_cpu0/channels# cat list_inuse 0 .../cti_cpu0/regs# echo 4 > inout_sel .../cti_cpu0/regs# echo 1 > outen .../cti_cpu0/channels# echo 0 > chan_set .../cti_cpu0/regs# cat trigoutstatus 0x10
Thanks, Leo Yan
diff --git a/Documentation/trace/coresight.txt
b/Documentation/trace/coresight.txt
index b027d61b27a6..f37d927a368c 100644 --- a/Documentation/trace/coresight.txt +++ b/Documentation/trace/coresight.txt @@ -477,6 +477,13 @@ root@genericarmv8:~#
Details on how to use the generic STM API can be found here [2].
+The CTI Module +--------------
+A separate documentation file is provided to explain the use of CTI
devices.
+(Documentation/trace/coresight-ect.txt)
[1]. Documentation/ABI/testing/sysfs-bus-coresight-devices-stm [2]. Documentation/trace/stm.rst [3]. https://github.com/Linaro/perf-opencsd diff --git a/MAINTAINERS b/MAINTAINERS index a81f3bd8340a..45cfe624cb8c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1585,6 +1585,7 @@ F: drivers/hwtracing/coresight/* F: include/dt-bindings/arm/coresight-cti-dt.h F: Documentation/trace/coresight.txt F: Documentation/trace/coresight-cpu-debug.txt +F: Documentation/trace/coresight-ect.txt F: Documentation/devicetree/bindings/arm/coresight.txt F: Documentation/devicetree/bindings/arm/coresight-cpu-debug.txt F: Documentation/devicetree/bindings/arm/coresight-ect-cti.txt -- 2.17.1
CoreSight mailing list CoreSight@lists.linaro.org https://lists.linaro.org/mailman/listinfo/coresight
Add API usage document for sysfs API in CTI driver.
Signed-off-by: Mike Leach mike.leach@linaro.org --- .../testing/sysfs-bus-coresight-devices-cti | 231 ++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-coresight-devices-cti
diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-cti b/Documentation/ABI/testing/sysfs-bus-coresight-devices-cti new file mode 100644 index 000000000000..83eef5896ff8 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-cti @@ -0,0 +1,231 @@ +What: /sys/bus/coresight/devices/<cti-name>/enable +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (RW) Enable/Disable the CTI hardware. + +What: /sys/bus/coresight/devices/<cti-name>/ctmid +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (R) Display the associated CTM ID + +What: /sys/bus/coresight/devices/<cti-name>/connections/nr_cons +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (R) Number of devices connected to this CTI + +What: /sys/bus/coresight/devices/<cti-name>/connections/trigout_filtered +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (R) List of output triggers filtered across all connections. + +What: /sys/bus/coresight/devices/<cti-name>/triggers<N>/name +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (R) Name of connected device <N> + +What: /sys/bus/coresight/devices/<cti-name>/triggers<N>/in_signals +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (R) Input trigger signals from connected device <N> + +What: /sys/bus/coresight/devices/<cti-name>/triggers<N>/in_types +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (R) Functional types for the input trigger signals + from connected device <N> + +What: /sys/bus/coresight/devices/<cti-name>/triggers<N>/out_signals +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (R) Output trigger signals to connected device <N> + +What: /sys/bus/coresight/devices/<cti-name>/triggers<N>/out_types +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (R) Functional types for the output trigger signals + to connected device <N> + +What: /sys/bus/coresight/devices/<cti-name>/regs/inout_sel +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (RW) Select the index for inen and outen registers. + +What: /sys/bus/coresight/devices/<cti-name>/regs/inen +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (RW) Read or write the CTIINEN register selected by inout_sel. + +What: /sys/bus/coresight/devices/<cti-name>/regs/outen +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (RW) Read or write the CTIOUTEN register selected by inout_sel. + +What: /sys/bus/coresight/devices/<cti-name>/regs/gate +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (RW) Read or write CTIGATE register. + +What: /sys/bus/coresight/devices/<cti-name>/regs/asicctl +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (RW) Read or write ASICCTL register. + +What: /sys/bus/coresight/devices/<cti-name>/regs/intack +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (W) Write the INTACK register. + +What: /sys/bus/coresight/devices/<cti-name>/regs/appset +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (RW) Set CTIAPPSET register to activate channel. Read back to + determine current value of register. + +What: /sys/bus/coresight/devices/<cti-name>/regs/appclear +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (W) Write APPCLEAR register to deactivate channel. + +What: /sys/bus/coresight/devices/<cti-name>/regs/apppulse +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (W) Write APPPULSE to pulse a channel active for one clock + cycle. + +What: /sys/bus/coresight/devices/<cti-name>/regs/chinstatus +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (R) Read current status of channel inputs. + +What: /sys/bus/coresight/devices/<cti-name>/regs/choutstatus +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (R) read current status of channel outputs. + +What: /sys/bus/coresight/devices/<cti-name>/regs/triginstatus +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (R) read current status of input trigger signals + +What: /sys/bus/coresight/devices/<cti-name>/regs/trigoutstatus +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (R) read current status of output trigger signals. + +What: /sys/bus/coresight/devices/<cti-name>/channels/trigin_attach +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (W) Attach a CTI input trigger to a CTM channel. + +What: /sys/bus/coresight/devices/<cti-name>/channels/trigin_detach +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (W) Detach a CTI input trigger from a CTM channel. + +What: /sys/bus/coresight/devices/<cti-name>/channels/trigout_attach +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (W) Attach a CTI output trigger to a CTM channel. + +What: /sys/bus/coresight/devices/<cti-name>/channels/trigout_detach +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (W) Detach a CTI output trigger from a CTM channel. + +What: /sys/bus/coresight/devices/<cti-name>/channels/gate_enable +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (W) Enable CTIGATE for single channel or all channels. + +What: /sys/bus/coresight/devices/<cti-name>/channels/gate_disable +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (W) Disable CTIGATE for single channel or all channels. + +What: /sys/bus/coresight/devices/<cti-name>/channels/chan_set +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (W) Activate a single channel. + +What: /sys/bus/coresight/devices/<cti-name>/channels/chan_clear +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (W) Deactivate a single channel. + +What: /sys/bus/coresight/devices/<cti-name>/channels/chan_pulse +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (W) Pulse a single channel - activate for a single clock cycle. + +What: /sys/bus/coresight/devices/<cti-name>/channels/trig_filter_enable +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (RW) Enable or disable trigger output signal filtering. + +What: /sys/bus/coresight/devices/<cti-name>/channels/list_gate_enable +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (R) Channels enabled through the gate. + +What: /sys/bus/coresight/devices/<cti-name>/channels/list_inuse +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (R) show channels with at least one attached trigger signal. + +What: /sys/bus/coresight/devices/<cti-name>/channels/list_free +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (R) show channels with no attached trigger signals. + +What: /sys/bus/coresight/devices/<cti-name>/channels/show_chan_sel +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (RW) Select a channel for the show_chan_xtrigs operation + +What: /sys/bus/coresight/devices/<cti-name>/channels/show_chan_xtrigs +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (R) Show triggers attached to selected channel on this CTI. + +What: /sys/bus/coresight/devices/<cti-name>/channels/reset_xtrigs +Date: Jul 2019 +KernelVersion 5.4 +Contact: Mike Leach or Mathieu Poirier +Description: (W) Clear all channel / trigger programming.
Hi Mike,
On Mon, Aug 19, 2019 at 10:13:46PM +0100, Mike Leach wrote:
CTIs are defined in the device tree and associated with other CoreSight devices. The core CoreSight code has been modified to enable the registration of the CTI devices on the same bus as the other CoreSight components, but as these are not actually trace generation / capture devices, they are not part of the Coresight path when generating trace.
However, the definition of the standard CoreSight device has been extended to include a reference to an associated CTI device, and the enable / disable trace path operations will auto enable/disable any associated CTI devices at the same time.
Programming is at present via sysfs - a full API is provided to utilise the hardware capabilities. As CTI devices are unprogrammed by default, the auto enable describe above will have no effect until explicit programming takes place.
A set of device tree bindings specific to the CTI topology has been defined. The driver accesses these in a platform agnostic manner, so ACPI bindings can be added later, once they have been agreed and defined for the CTI device.
Documentation has been updated to describe both the CTI hardware, its use and programming in sysfs, and the new dts bindings required.
Tested on DB410 board, applies on coresight/next tree - 5.3-rc1 based.
I tested this patch set on my Hikey620 board with below commands (and also applied below patch for CTI DT binding); I can confirm below testing can work well on Hikey board; FWIW:
Tested-by: Leo Yan leo.yan@linaro.org
Testing commands:
.../cti_cpu0# echo 1 > enable .../cti_cpu0/channels# echo 0 4 > trigout_attach .../cti_sys0/channels# echo 0 > show_chan_sel .../cti_cpu0/channels# cat show_chan_xtrigs IN: OUT: 4 .../cti_cpu0/regs# echo 4 > inout_sel .../cti_cpu0/regs# echo 1 > outen .../cti_cpu0/channels# echo 0 > chan_set .../cti_cpu0/regs# cat trigoutstatus 0x10
---8<---
diff --git a/arch/arm64/boot/dts/hisilicon/hi6220-coresight.dtsi b/arch/arm64/boot/dts/hisilicon/hi6220-coresight.dtsi index 651771a73ed6..806f0526f18f 100644 --- a/arch/arm64/boot/dts/hisilicon/hi6220-coresight.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hi6220-coresight.dtsi @@ -213,7 +213,7 @@ }; };
- etm@f659c000 { + etm0: etm@f659c000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf659c000 0 0x1000>;
@@ -232,7 +232,7 @@ }; };
- etm@f659d000 { + etm1: etm@f659d000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf659d000 0 0x1000>;
@@ -251,7 +251,7 @@ }; };
- etm@f659e000 { + etm2: etm@f659e000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf659e000 0 0x1000>;
@@ -270,7 +270,7 @@ }; };
- etm@f659f000 { + etm3: etm@f659f000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf659f000 0 0x1000>;
@@ -289,7 +289,7 @@ }; };
- etm@f65dc000 { + etm4: etm@f65dc000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf65dc000 0 0x1000>;
@@ -308,7 +308,7 @@ }; };
- etm@f65dd000 { + etm5: etm@f65dd000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf65dd000 0 0x1000>;
@@ -327,7 +327,7 @@ }; };
- etm@f65de000 { + etm6: etm@f65de000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf65de000 0 0x1000>;
@@ -346,7 +346,7 @@ }; };
- etm@f65df000 { + etm7: etm@f65df000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf65df000 0 0x1000>;
@@ -364,5 +364,119 @@ }; }; }; + + /* System CTIs */ + /* CTI 0 - TMC and TPIU connections */ + cti@f6403000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0 0xf6403000 0 0x1000>; + + clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>; + clock-names = "apb_pclk"; + }; + + /* CTI - CPU-0 */ + cti@f6598000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0 0xf6598000 0 0x1000>; + + clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>; + clock-names = "apb_pclk"; + + arm,cti-v8-arch; + cpu = <&cpu0>; + arm,cs-dev-assoc = <&etm0>; + }; + + /* CTI - CPU-1 */ + cti@f6599000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0 0xf6599000 0 0x1000>; + + clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>; + clock-names = "apb_pclk"; + + arm,cti-v8-arch; + cpu = <&cpu1>; + arm,cs-dev-assoc = <&etm1>; + }; + + /* CTI - CPU-2 */ + cti@f659a000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0 0xf659a000 0 0x1000>; + + clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>; + clock-names = "apb_pclk"; + + arm,cti-v8-arch; + cpu = <&cpu2>; + arm,cs-dev-assoc = <&etm2>; + }; + + /* CTI - CPU-3 */ + cti@f659b000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0 0xf659b000 0 0x1000>; + + clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>; + clock-names = "apb_pclk"; + + arm,cti-v8-arch; + cpu = <&cpu3>; + arm,cs-dev-assoc = <&etm3>; + }; + + /* CTI - CPU-4 */ + cti@f65d8000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0 0xf65d8000 0 0x1000>; + + clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>; + clock-names = "apb_pclk"; + + arm,cti-v8-arch; + cpu = <&cpu4>; + arm,cs-dev-assoc = <&etm4>; + }; + + /* CTI - CPU-5 */ + cti@f65d9000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0 0xf65d9000 0 0x1000>; + + clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>; + clock-names = "apb_pclk"; + + arm,cti-v8-arch; + cpu = <&cpu5>; + arm,cs-dev-assoc = <&etm5>; + }; + + /* CTI - CPU-6 */ + cti@f65da000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0 0xf65da000 0 0x1000>; + + clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>; + clock-names = "apb_pclk"; + + arm,cti-v8-arch; + cpu = <&cpu6>; + arm,cs-dev-assoc = <&etm6>; + }; + + /* CTI - CPU-7 */ + cti@f65db000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0 0xf65db000 0 0x1000>; + + clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>; + clock-names = "apb_pclk"; + + arm,cti-v8-arch; + cpu = <&cpu7>; + arm,cs-dev-assoc = <&etm7>; + }; }; };
Hi Leo,
On Tue, 3 Sep 2019 at 09:06, Leo Yan leo.yan@linaro.org wrote:
Hi Mike,
On Mon, Aug 19, 2019 at 10:13:46PM +0100, Mike Leach wrote:
CTIs are defined in the device tree and associated with other CoreSight devices. The core CoreSight code has been modified to enable the registration of the CTI devices on the same bus as the other CoreSight components, but as these are not actually trace generation / capture devices, they are not part of the Coresight path when generating trace.
However, the definition of the standard CoreSight device has been extended to include a reference to an associated CTI device, and the enable / disable trace path operations will auto enable/disable any associated CTI devices at the same time.
Programming is at present via sysfs - a full API is provided to utilise the hardware capabilities. As CTI devices are unprogrammed by default, the auto enable describe above will have no effect until explicit programming takes place.
A set of device tree bindings specific to the CTI topology has been defined. The driver accesses these in a platform agnostic manner, so ACPI bindings can be added later, once they have been agreed and defined for the CTI device.
Documentation has been updated to describe both the CTI hardware, its use and programming in sysfs, and the new dts bindings required.
Tested on DB410 board, applies on coresight/next tree - 5.3-rc1 based.
I tested this patch set on my Hikey620 board with below commands (and also applied below patch for CTI DT binding); I can confirm below testing can work well on Hikey board; FWIW:
Tested-by: Leo Yan leo.yan@linaro.org
Thanks for testing this. I'll add your binding patch into the next set.
Mike
Testing commands:
.../cti_cpu0# echo 1 > enable .../cti_cpu0/channels# echo 0 4 > trigout_attach .../cti_sys0/channels# echo 0 > show_chan_sel .../cti_cpu0/channels# cat show_chan_xtrigs IN: OUT: 4 .../cti_cpu0/regs# echo 4 > inout_sel .../cti_cpu0/regs# echo 1 > outen .../cti_cpu0/channels# echo 0 > chan_set .../cti_cpu0/regs# cat trigoutstatus 0x10
---8<---
diff --git a/arch/arm64/boot/dts/hisilicon/hi6220-coresight.dtsi b/arch/arm64/boot/dts/hisilicon/hi6220-coresight.dtsi index 651771a73ed6..806f0526f18f 100644 --- a/arch/arm64/boot/dts/hisilicon/hi6220-coresight.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hi6220-coresight.dtsi @@ -213,7 +213,7 @@ }; };
etm@f659c000 {
etm0: etm@f659c000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf659c000 0 0x1000>;
@@ -232,7 +232,7 @@ }; };
etm@f659d000 {
etm1: etm@f659d000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf659d000 0 0x1000>;
@@ -251,7 +251,7 @@ }; };
etm@f659e000 {
etm2: etm@f659e000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf659e000 0 0x1000>;
@@ -270,7 +270,7 @@ }; };
etm@f659f000 {
etm3: etm@f659f000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf659f000 0 0x1000>;
@@ -289,7 +289,7 @@ }; };
etm@f65dc000 {
etm4: etm@f65dc000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf65dc000 0 0x1000>;
@@ -308,7 +308,7 @@ }; };
etm@f65dd000 {
etm5: etm@f65dd000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf65dd000 0 0x1000>;
@@ -327,7 +327,7 @@ }; };
etm@f65de000 {
etm6: etm@f65de000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf65de000 0 0x1000>;
@@ -346,7 +346,7 @@ }; };
etm@f65df000 {
etm7: etm@f65df000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf65df000 0 0x1000>;
@@ -364,5 +364,119 @@ }; }; };
/* System CTIs */
/* CTI 0 - TMC and TPIU connections */
cti@f6403000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0 0xf6403000 0 0x1000>;
clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>;
clock-names = "apb_pclk";
};
/* CTI - CPU-0 */
cti@f6598000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0 0xf6598000 0 0x1000>;
clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&cpu0>;
arm,cs-dev-assoc = <&etm0>;
};
/* CTI - CPU-1 */
cti@f6599000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0 0xf6599000 0 0x1000>;
clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&cpu1>;
arm,cs-dev-assoc = <&etm1>;
};
/* CTI - CPU-2 */
cti@f659a000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0 0xf659a000 0 0x1000>;
clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&cpu2>;
arm,cs-dev-assoc = <&etm2>;
};
/* CTI - CPU-3 */
cti@f659b000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0 0xf659b000 0 0x1000>;
clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&cpu3>;
arm,cs-dev-assoc = <&etm3>;
};
/* CTI - CPU-4 */
cti@f65d8000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0 0xf65d8000 0 0x1000>;
clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&cpu4>;
arm,cs-dev-assoc = <&etm4>;
};
/* CTI - CPU-5 */
cti@f65d9000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0 0xf65d9000 0 0x1000>;
clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&cpu5>;
arm,cs-dev-assoc = <&etm5>;
};
/* CTI - CPU-6 */
cti@f65da000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0 0xf65da000 0 0x1000>;
clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&cpu6>;
arm,cs-dev-assoc = <&etm6>;
};
/* CTI - CPU-7 */
cti@f65db000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0 0xf65db000 0 0x1000>;
clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&cpu7>;
arm,cs-dev-assoc = <&etm7>;
}; };
};
On Tue, Sep 03, 2019 at 10:17:51AM +0100, Mike Leach wrote:
Hi Leo,
On Tue, 3 Sep 2019 at 09:06, Leo Yan leo.yan@linaro.org wrote:
Hi Mike,
On Mon, Aug 19, 2019 at 10:13:46PM +0100, Mike Leach wrote:
CTIs are defined in the device tree and associated with other CoreSight devices. The core CoreSight code has been modified to enable the registration of the CTI devices on the same bus as the other CoreSight components, but as these are not actually trace generation / capture devices, they are not part of the Coresight path when generating trace.
However, the definition of the standard CoreSight device has been extended to include a reference to an associated CTI device, and the enable / disable trace path operations will auto enable/disable any associated CTI devices at the same time.
Programming is at present via sysfs - a full API is provided to utilise the hardware capabilities. As CTI devices are unprogrammed by default, the auto enable describe above will have no effect until explicit programming takes place.
A set of device tree bindings specific to the CTI topology has been defined. The driver accesses these in a platform agnostic manner, so ACPI bindings can be added later, once they have been agreed and defined for the CTI device.
Documentation has been updated to describe both the CTI hardware, its use and programming in sysfs, and the new dts bindings required.
Tested on DB410 board, applies on coresight/next tree - 5.3-rc1 based.
I tested this patch set on my Hikey620 board with below commands (and also applied below patch for CTI DT binding); I can confirm below testing can work well on Hikey board; FWIW:
Tested-by: Leo Yan leo.yan@linaro.org
Thanks for testing this. I'll add your binding patch into the next set.
Welcome and appreciate for this!
[...]
Thanks, Leo Yan
On Tue, Sep 03, 2019 at 10:17:51AM +0100, Mike Leach wrote:
Hi Leo,
On Tue, 3 Sep 2019 at 09:06, Leo Yan leo.yan@linaro.org wrote:
Hi Mike,
On Mon, Aug 19, 2019 at 10:13:46PM +0100, Mike Leach wrote:
CTIs are defined in the device tree and associated with other CoreSight devices. The core CoreSight code has been modified to enable the registration of the CTI devices on the same bus as the other CoreSight components, but as these are not actually trace generation / capture devices, they are not part of the Coresight path when generating trace.
However, the definition of the standard CoreSight device has been extended to include a reference to an associated CTI device, and the enable / disable trace path operations will auto enable/disable any associated CTI devices at the same time.
Programming is at present via sysfs - a full API is provided to utilise the hardware capabilities. As CTI devices are unprogrammed by default, the auto enable describe above will have no effect until explicit programming takes place.
A set of device tree bindings specific to the CTI topology has been defined. The driver accesses these in a platform agnostic manner, so ACPI bindings can be added later, once they have been agreed and defined for the CTI device.
Documentation has been updated to describe both the CTI hardware, its use and programming in sysfs, and the new dts bindings required.
Tested on DB410 board, applies on coresight/next tree - 5.3-rc1 based.
I tested this patch set on my Hikey620 board with below commands (and also applied below patch for CTI DT binding); I can confirm below testing can work well on Hikey board; FWIW:
Tested-by: Leo Yan leo.yan@linaro.org
Thanks for testing this. I'll add your binding patch into the next set.
Mike
Testing commands:
.../cti_cpu0# echo 1 > enable .../cti_cpu0/channels# echo 0 4 > trigout_attach .../cti_sys0/channels# echo 0 > show_chan_sel .../cti_cpu0/channels# cat show_chan_xtrigs IN: OUT: 4 .../cti_cpu0/regs# echo 4 > inout_sel .../cti_cpu0/regs# echo 1 > outen .../cti_cpu0/channels# echo 0 > chan_set .../cti_cpu0/regs# cat trigoutstatus 0x10
---8<---
diff --git a/arch/arm64/boot/dts/hisilicon/hi6220-coresight.dtsi b/arch/arm64/boot/dts/hisilicon/hi6220-coresight.dtsi index 651771a73ed6..806f0526f18f 100644 --- a/arch/arm64/boot/dts/hisilicon/hi6220-coresight.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hi6220-coresight.dtsi @@ -213,7 +213,7 @@ }; };
etm@f659c000 {
etm0: etm@f659c000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf659c000 0 0x1000>;
@@ -232,7 +232,7 @@ }; };
etm@f659d000 {
etm1: etm@f659d000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf659d000 0 0x1000>;
@@ -251,7 +251,7 @@ }; };
etm@f659e000 {
etm2: etm@f659e000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf659e000 0 0x1000>;
@@ -270,7 +270,7 @@ }; };
etm@f659f000 {
etm3: etm@f659f000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf659f000 0 0x1000>;
@@ -289,7 +289,7 @@ }; };
etm@f65dc000 {
etm4: etm@f65dc000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf65dc000 0 0x1000>;
@@ -308,7 +308,7 @@
}; };
etm@f65dd000 {
etm5: etm@f65dd000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf65dd000 0 0x1000>;
@@ -327,7 +327,7 @@ }; };
etm@f65de000 {
etm6: etm@f65de000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf65de000 0 0x1000>;
@@ -346,7 +346,7 @@ }; };
etm@f65df000 {
etm7: etm@f65df000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0xf65df000 0 0x1000>;
@@ -364,5 +364,119 @@ }; }; };
/* System CTIs */
/* CTI 0 - TMC and TPIU connections */
cti@f6403000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0 0xf6403000 0 0x1000>;
clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>;
clock-names = "apb_pclk";
};
/* CTI - CPU-0 */
cti@f6598000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0 0xf6598000 0 0x1000>;
clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&cpu0>;
arm,cs-dev-assoc = <&etm0>;
};
/* CTI - CPU-1 */
cti@f6599000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0 0xf6599000 0 0x1000>;
clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&cpu1>;
arm,cs-dev-assoc = <&etm1>;
};
/* CTI - CPU-2 */
cti@f659a000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0 0xf659a000 0 0x1000>;
clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&cpu2>;
arm,cs-dev-assoc = <&etm2>;
};
/* CTI - CPU-3 */
cti@f659b000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0 0xf659b000 0 0x1000>;
clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&cpu3>;
arm,cs-dev-assoc = <&etm3>;
};
/* CTI - CPU-4 */
cti@f65d8000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0 0xf65d8000 0 0x1000>;
clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&cpu4>;
arm,cs-dev-assoc = <&etm4>;
};
/* CTI - CPU-5 */
cti@f65d9000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0 0xf65d9000 0 0x1000>;
clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&cpu5>;
arm,cs-dev-assoc = <&etm5>;
};
/* CTI - CPU-6 */
cti@f65da000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0 0xf65da000 0 0x1000>;
clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&cpu6>;
arm,cs-dev-assoc = <&etm6>;
};
/* CTI - CPU-7 */
cti@f65db000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0 0xf65db000 0 0x1000>;
clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&cpu7>;
arm,cs-dev-assoc = <&etm7>;
};
For the hikey620 DT bindings:
Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org
};
};
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK