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 after following dependent set applied for documentation directory changes [1]. Kernel version 5.4-rc7.
[1] https://www.spinics.net/lists/linux-doc/msg71062.html
Changes since v4: Multiple changes following feedback from Mathieu, Leo and Suzuki. 1) Dropped RFC tag - wider distribution 2) CTI bindings definition now presented as a .yaml file - tested with with 'dt-doc-validate' from devicetree.org/dt-schema project and in kernel build tree with 'make dtbs_check' per kernel docs. 3) Sysfs links to other CoreSight devices moved out of this set into a following set that deals with all CoreSight devices & sysfs links. 4) Documentation in .rst format and new directory following patchset in [1]. Extended example provided in docs. 5) Rationalised devicetree of_ specifics to use generic fwnode functions where possible to enable easier addition of ACPI support later. 6) Other minor changes as requested in feedback from last patchset.
Changes since v3: 1) After discussion on CS mailing list, each CTI connection has a triggers<N> sysfs directory with name and trigger signals listed for the connection. 2) 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. 3) Power management - CPU hotplug and idle omitted from this set as ongoing developments may define required direction. Additional patch set to follow. 4) 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 (14): 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 dt-bindings: qcom: Add CTI options for qcom msm8916 dt-bindings: arm: Juno platform - add CTI entries to device tree. dt-bindings: hisilicon: Add CTI bindings for hi-6220 docs: coresight: Update documentation for CoreSight to cover CTI. docs: sysfs: coresight: Add sysfs ABI documentation for CTI
.../testing/sysfs-bus-coresight-devices-cti | 221 +++ .../bindings/arm/coresight-cti.yaml | 303 ++++ .../devicetree/bindings/arm/coresight.txt | 7 + .../trace/coresight/coresight-ect.rst | 200 +++ Documentation/trace/coresight/coresight.rst | 13 + MAINTAINERS | 2 + arch/arm64/boot/dts/arm/juno-base.dtsi | 150 +- 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 + .../boot/dts/hisilicon/hi6220-coresight.dtsi | 130 +- arch/arm64/boot/dts/qcom/msm8916.dtsi | 85 +- drivers/hwtracing/coresight/Kconfig | 12 + drivers/hwtracing/coresight/Makefile | 3 + .../coresight/coresight-cti-platform.c | 500 +++++++ .../hwtracing/coresight/coresight-cti-sysfs.c | 1219 +++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.c | 712 ++++++++++ drivers/hwtracing/coresight/coresight-cti.h | 232 ++++ .../hwtracing/coresight/coresight-platform.c | 23 + drivers/hwtracing/coresight/coresight-priv.h | 7 + drivers/hwtracing/coresight/coresight.c | 61 +- include/dt-bindings/arm/coresight-cti-dt.h | 37 + include/linux/coresight.h | 28 + 24 files changed, 4028 insertions(+), 23 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-bus-coresight-devices-cti create mode 100644 Documentation/devicetree/bindings/arm/coresight-cti.yaml create mode 100644 Documentation/trace/coresight/coresight-ect.rst 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 | 3 + .../coresight/coresight-cti-platform.c | 53 +++ .../hwtracing/coresight/coresight-cti-sysfs.c | 72 +++ drivers/hwtracing/coresight/coresight-cti.c | 448 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.h | 186 ++++++++ drivers/hwtracing/coresight/coresight.c | 3 + include/linux/coresight.h | 23 + 8 files changed, 800 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 6ff30e25af55..45d3822c8c8c 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -110,4 +110,16 @@ config CORESIGHT_CPU_DEBUG properly, please refer Documentation/trace/coresight-cpu-debug.rst 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..0e3e72f0f510 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -17,3 +17,6 @@ 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..665be86c585d --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019, The Linaro Limited. All rights reserved. + */ + +#include <linux/of.h> + +#include "coresight-cti.h" + +/* get the hardware configuration & connection data. */ +int cti_plat_get_hw_data(struct device *dev, + 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; +} + +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); + struct cti_drvdata *drvdata = dev_get_drvdata(dev); + + if (IS_ERR_OR_NULL(fwnode)) + goto error; + + /* + * Alloc platform data but leave it zero init. CTI does not use the + * same connection infrastructuree as trace path components but an + * empty struct enables us to use the standard coresight component + * registration code. + */ + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + ret = -ENOMEM; + goto error; + } + + /* get some CTI specifics */ + ret = cti_plat_get_hw_data(dev, drvdata); + + 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..7ae48bf62d17 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -0,0 +1,448 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 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 */ +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) +{ + 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; + atomic_inc(&drvdata->config.enable_req_count); + spin_unlock(&drvdata->spinlock); + return rc; + +cti_state_unchanged: + 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) +{ + struct cti_config *config = &drvdata->config; + struct device *dev = &drvdata->csdev->dev; + + spin_lock(&drvdata->spinlock); + + /* check refcount - disable on 0 */ + if (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); +} + +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); +} + +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); + break; + } + } + 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(&drvdata->csdev->dev, "CTI initialized\n"); + 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..e0d476533a82 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -0,0 +1,186 @@ +/* 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 + * + * @nr_trig_max: Max number of trigger signals implemented on device. + * (max of trig_in or trig_out) - from ID register. + * @nr_ctm_channels: number of available CTM channels - from ID register. + * @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. + * @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. + * @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 ef20f74c85fa..1a5fdf2710ff 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -955,6 +955,9 @@ static struct device_type coresight_dev_type[] = { { .name = "helper", }, + { + .name = "ect", + }, };
static void coresight_device_release(struct device *dev) diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 44e552de419c..b3e582d96a34 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
On Tue, Nov 19, 2019 at 11:18:59PM +0000, 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 | 3 + .../coresight/coresight-cti-platform.c | 53 +++ .../hwtracing/coresight/coresight-cti-sysfs.c | 72 +++ drivers/hwtracing/coresight/coresight-cti.c | 448 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.h | 186 ++++++++ drivers/hwtracing/coresight/coresight.c | 3 + include/linux/coresight.h | 23 + 8 files changed, 800 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 6ff30e25af55..45d3822c8c8c 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -110,4 +110,16 @@ config CORESIGHT_CPU_DEBUG properly, please refer Documentation/trace/coresight-cpu-debug.rst 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..0e3e72f0f510 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -17,3 +17,6 @@ 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..665be86c585d --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2019, The Linaro Limited. All rights reserved.
- */
+#include <linux/of.h>
+#include "coresight-cti.h"
+/* get the hardware configuration & connection data. */ +int cti_plat_get_hw_data(struct device *dev,
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;
+}
+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);
- struct cti_drvdata *drvdata = dev_get_drvdata(dev);
- if (IS_ERR_OR_NULL(fwnode))
goto error;
- /*
* Alloc platform data but leave it zero init. CTI does not use the
* same connection infrastructuree as trace path components but an
* empty struct enables us to use the standard coresight component
* registration code.
*/
- pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
ret = -ENOMEM;
goto error;
- }
- /* get some CTI specifics */
- ret = cti_plat_get_hw_data(dev, drvdata);
- 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..7ae48bf62d17 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -0,0 +1,448 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2018 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 */ +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) +{
- 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;
- atomic_inc(&drvdata->config.enable_req_count);
- spin_unlock(&drvdata->spinlock);
- return rc;
+cti_state_unchanged:
- 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) +{
- struct cti_config *config = &drvdata->config;
- struct device *dev = &drvdata->csdev->dev;
- spin_lock(&drvdata->spinlock);
- /* check refcount - disable on 0 */
- if (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);
+}
+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);
+}
+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);
break;
}
- }
- 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);
Here I would simply call cti_plat_get_hw_data() and not instantiate a *pdata. See below for more details.
- 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;
Just set this to NULL and add a check in coresight_release_platform_data() that returns immediately if @pdata is NULL. The latter should be done in a separate patch preceding this one. If someone tries to do a cti_drvdata::csdev::pdata, we'll find out pretty quickly.
With this: Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org
- 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(&drvdata->csdev->dev, "CTI initialized\n");
- 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..e0d476533a82 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -0,0 +1,186 @@ +/* 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
- @nr_trig_max: Max number of trigger signals implemented on device.
(max of trig_in or trig_out) - from ID register.
- @nr_ctm_channels: number of available CTM channels - from ID register.
- @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.
- @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.
- @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 ef20f74c85fa..1a5fdf2710ff 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -955,6 +955,9 @@ static struct device_type coresight_dev_type[] = { { .name = "helper", },
- {
.name = "ect",
- },
}; static void coresight_device_release(struct device *dev) diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 44e552de419c..b3e582d96a34 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 Mathieu,
On Thu, 21 Nov 2019 at 20:21, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Tue, Nov 19, 2019 at 11:18:59PM +0000, 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 | 3 + .../coresight/coresight-cti-platform.c | 53 +++ .../hwtracing/coresight/coresight-cti-sysfs.c | 72 +++ drivers/hwtracing/coresight/coresight-cti.c | 448 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.h | 186 ++++++++ drivers/hwtracing/coresight/coresight.c | 3 + include/linux/coresight.h | 23 + 8 files changed, 800 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 6ff30e25af55..45d3822c8c8c 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -110,4 +110,16 @@ config CORESIGHT_CPU_DEBUG properly, please refer Documentation/trace/coresight-cpu-debug.rst 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..0e3e72f0f510 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -17,3 +17,6 @@ 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..665be86c585d --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2019, The Linaro Limited. All rights reserved.
- */
+#include <linux/of.h>
+#include "coresight-cti.h"
+/* get the hardware configuration & connection data. */ +int cti_plat_get_hw_data(struct device *dev,
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;
+}
+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);
struct cti_drvdata *drvdata = dev_get_drvdata(dev);
if (IS_ERR_OR_NULL(fwnode))
goto error;
/*
* Alloc platform data but leave it zero init. CTI does not use the
* same connection infrastructuree as trace path components but an
* empty struct enables us to use the standard coresight component
* registration code.
*/
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
ret = -ENOMEM;
goto error;
}
/* get some CTI specifics */
ret = cti_plat_get_hw_data(dev, drvdata);
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..7ae48bf62d17 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -0,0 +1,448 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2018 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 */ +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) +{
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;
atomic_inc(&drvdata->config.enable_req_count);
spin_unlock(&drvdata->spinlock);
return rc;
+cti_state_unchanged:
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) +{
struct cti_config *config = &drvdata->config;
struct device *dev = &drvdata->csdev->dev;
spin_lock(&drvdata->spinlock);
/* check refcount - disable on 0 */
if (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);
+}
+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);
+}
+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);
break;
}
}
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);
Here I would simply call cti_plat_get_hw_data() and not instantiate a *pdata. See below for more details.
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;
Just set this to NULL and add a check in coresight_release_platform_data() that returns immediately if @pdata is NULL. The latter should be done in a separate patch preceding this one. If someone tries to do a cti_drvdata::csdev::pdata, we'll find out pretty quickly.
With this: Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org
pdata is used later in the generic coresight_register function. We need it to pass to this with 0 connection ports as we define connections differently - but we need to allow the rest of the common infrastructure to keep working for us.
Regards
Mike
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(&drvdata->csdev->dev, "CTI initialized\n");
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..e0d476533a82 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -0,0 +1,186 @@ +/* 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
- @nr_trig_max: Max number of trigger signals implemented on device.
(max of trig_in or trig_out) - from ID register.
- @nr_ctm_channels: number of available CTM channels - from ID register.
- @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.
- @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.
- @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 ef20f74c85fa..1a5fdf2710ff 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -955,6 +955,9 @@ static struct device_type coresight_dev_type[] = { { .name = "helper", },
{
.name = "ect",
},
};
static void coresight_device_release(struct device *dev) diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 44e552de419c..b3e582d96a34 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 Fri, 29 Nov 2019 at 05:05, Mike Leach mike.leach@linaro.org wrote:
Hi Mathieu,
On Thu, 21 Nov 2019 at 20:21, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Tue, Nov 19, 2019 at 11:18:59PM +0000, 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 | 3 + .../coresight/coresight-cti-platform.c | 53 +++ .../hwtracing/coresight/coresight-cti-sysfs.c | 72 +++ drivers/hwtracing/coresight/coresight-cti.c | 448 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.h | 186 ++++++++ drivers/hwtracing/coresight/coresight.c | 3 + include/linux/coresight.h | 23 + 8 files changed, 800 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 6ff30e25af55..45d3822c8c8c 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -110,4 +110,16 @@ config CORESIGHT_CPU_DEBUG properly, please refer Documentation/trace/coresight-cpu-debug.rst 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..0e3e72f0f510 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -17,3 +17,6 @@ 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..665be86c585d --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2019, The Linaro Limited. All rights reserved.
- */
+#include <linux/of.h>
+#include "coresight-cti.h"
+/* get the hardware configuration & connection data. */ +int cti_plat_get_hw_data(struct device *dev,
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;
+}
+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);
struct cti_drvdata *drvdata = dev_get_drvdata(dev);
if (IS_ERR_OR_NULL(fwnode))
goto error;
/*
* Alloc platform data but leave it zero init. CTI does not use the
* same connection infrastructuree as trace path components but an
* empty struct enables us to use the standard coresight component
* registration code.
*/
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
ret = -ENOMEM;
goto error;
}
/* get some CTI specifics */
ret = cti_plat_get_hw_data(dev, drvdata);
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..7ae48bf62d17 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -0,0 +1,448 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2018 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 */ +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) +{
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;
atomic_inc(&drvdata->config.enable_req_count);
spin_unlock(&drvdata->spinlock);
return rc;
+cti_state_unchanged:
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) +{
struct cti_config *config = &drvdata->config;
struct device *dev = &drvdata->csdev->dev;
spin_lock(&drvdata->spinlock);
/* check refcount - disable on 0 */
if (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);
+}
+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);
+}
+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);
break;
}
}
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);
Here I would simply call cti_plat_get_hw_data() and not instantiate a *pdata. See below for more details.
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;
Just set this to NULL and add a check in coresight_release_platform_data() that returns immediately if @pdata is NULL. The latter should be done in a separate patch preceding this one. If someone tries to do a cti_drvdata::csdev::pdata, we'll find out pretty quickly.
With this: Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org
pdata is used later in the generic coresight_register function. We need it to pass to this with 0 connection ports as we define connections differently - but we need to allow the rest of the common infrastructure to keep working for us.
I investigated this further and you are correct, the pdata is used quite often throughout the framework to manage connections between data components. Provisioning for a NULL pdata would require a fair amount of changes not related to this work.
Mathieu
Regards
Mike
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(&drvdata->csdev->dev, "CTI initialized\n");
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..e0d476533a82 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -0,0 +1,186 @@ +/* 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
- @nr_trig_max: Max number of trigger signals implemented on device.
(max of trig_in or trig_out) - from ID register.
- @nr_ctm_channels: number of available CTM channels - from ID register.
- @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.
- @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.
- @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 ef20f74c85fa..1a5fdf2710ff 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -955,6 +955,9 @@ static struct device_type coresight_dev_type[] = { { .name = "helper", },
{
.name = "ect",
},
};
static void coresight_device_release(struct device *dev) diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 44e552de419c..b3e582d96a34 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
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
On 19/11/2019 23:18, 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
Looks good to me. Some very minor nits, feel free to ignore if you are not respinning the series.
+/*
- 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)
BMVAL(devid_val, 15, 8)
+/* DEVID[19:16] - number of CTM channels */ +#define CTI_DEVID_CTMCHANNELS(devid_val) (int)((devid_val & 0xF0000) >> 16)
BMVAL(devid_val, 19, 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;
Do we need to make sure that they are exclusive ?
WARN_ON(drvdata->config.trig_in_use ^ ~(tc->con_in->used_mask)); WARN_ON(drvdata->config.trig_out_use ^ ~(tc->con_out->used_mask));
+/** cti ect operations **/ +int cti_enable(struct coresight_device *csdev) +{
- struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev);
- /* enable hardware with refcount */
nit: left over comment from previous revision ?
- return cti_enable_hw(drvdata);
+}
+int cti_disable(struct coresight_device *csdev) +{
- struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev);
- /* disable hardware with refcount */
same here ?
- return cti_disable_hw(drvdata);
+}
+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__);
dev_err() ? As they may have higher priority than "info" and will get displayed in the rare chance of them getting hit.
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__);
same here, dev_err()
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 */
minor nit: I would not mention about ".dts" here. The function name is implicit. You could actually remove that comment.
As mentioned above, the comments are minor nits. So you may add with/without addressing them:
Reviewed-by: Suzuki K Poulose suzuki.poulose@arm.com
Hi Suzuki,
Will be re-spinning due to later patches - so will fixup as requested
Thanks
Mike
On Mon, 25 Nov 2019 at 19:03, Suzuki Kuruppassery Poulose suzuki.poulose@arm.com wrote:
On 19/11/2019 23:18, 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
Looks good to me. Some very minor nits, feel free to ignore if you are not respinning the series.
+/*
- 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)
BMVAL(devid_val, 15, 8)
+/* DEVID[19:16] - number of CTM channels */ +#define CTI_DEVID_CTMCHANNELS(devid_val) (int)((devid_val & 0xF0000) >> 16)
BMVAL(devid_val, 19, 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;
Do we need to make sure that they are exclusive ?
WARN_ON(drvdata->config.trig_in_use ^ ~(tc->con_in->used_mask)); WARN_ON(drvdata->config.trig_out_use ^ ~(tc->con_out->used_mask));
+/** cti ect operations **/ +int cti_enable(struct coresight_device *csdev) +{
struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev);
/* enable hardware with refcount */
nit: left over comment from previous revision ?
return cti_enable_hw(drvdata);
+}
+int cti_disable(struct coresight_device *csdev) +{
struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev);
/* disable hardware with refcount */
same here ?
return cti_disable_hw(drvdata);
+}
+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__);
dev_err() ? As they may have higher priority than "info" and will get displayed in the rare chance of them getting hit.
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__);
same here, dev_err()
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 */
minor nit: I would not mention about ".dts" here. The function name is implicit. You could actually remove that comment.
As mentioned above, the comments are minor nits. So you may add with/without addressing them:
Reviewed-by: Suzuki K Poulose suzuki.poulose@arm.com
Adds sysfs access to the coresight management registers.
Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org Reviewed-by: Suzuki K Poulose suzuki.poulose@arm.com Signed-off-by: Mike Leach mike.leach@linaro.org --- .../hwtracing/coresight/coresight-cti-sysfs.c | 53 +++++++++++++++++++ drivers/hwtracing/coresight/coresight-priv.h | 1 + 2 files changed, 54 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index a832b8c6b866..507f8eb487fe 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -62,11 +62,64 @@ static struct attribute *coresight_cti_attrs[] = { 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, +}; + 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 Tue, Nov 19, 2019 at 11:19:00PM +0000, Mike Leach wrote:
Adds sysfs access to the coresight management registers.
Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org Reviewed-by: Suzuki K Poulose suzuki.poulose@arm.com Signed-off-by: Mike Leach mike.leach@linaro.org
Tags added to a patch are like a chain of custody and should be added in order they were published. In this case you wrote the patch so your SoB goes first. Then Suzuki and I have reviewed your patch and as such, our RB come _after_ your SoB. When I add the patch to my tree I'll add my SoB after that and when Greg picks it up in his, he will do the same. Please re-order the tags in this patch and the other ones in this set to reflect the chronology of events.
.../hwtracing/coresight/coresight-cti-sysfs.c | 53 +++++++++++++++++++ drivers/hwtracing/coresight/coresight-priv.h | 1 + 2 files changed, 54 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index a832b8c6b866..507f8eb487fe 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -62,11 +62,64 @@ static struct attribute *coresight_cti_attrs[] = { 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,
+};
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
Adds in sysfs programming support for the CTI function register sets. Allows direct manipulation of channel / trigger association registers.
Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org Signed-off-by: Mike Leach mike.leach@linaro.org --- .../hwtracing/coresight/coresight-cti-sysfs.c | 362 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.c | 19 + drivers/hwtracing/coresight/coresight-cti.h | 5 + 3 files changed, 386 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 507f8eb487fe..02d3ee0c1278 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -109,6 +109,362 @@ 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); + + /* 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, }; @@ -118,8 +474,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 7ae48bf62d17..b016b1e67fb1 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -149,6 +149,25 @@ static int cti_disable_hw(struct cti_drvdata *drvdata) 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 e0d476533a82..73869fa8b313 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -180,7 +180,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 19/11/2019 23:19, Mike Leach wrote:
Adds in sysfs programming support for the CTI function register sets. Allows direct manipulation of channel / trigger association registers.
Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-cti-sysfs.c | 362 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.c | 19 + drivers/hwtracing/coresight/coresight-cti.h | 5 + 3 files changed, 386 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 507f8eb487fe..02d3ee0c1278 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -109,6 +109,362 @@ 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.
- */
Also I am not sure if it makes sense to mention that the value is cached.
+static ssize_t cti_reg32_show(struct device *dev, char *buf,
u32 *pcached_val, int reg_offset)
+{
- u32 val = 0;
+ char *state = "";
- 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)) {
minor nit: Personally I don't like the naming here. This could simply be: cti_accessible(config) , may be defined as a static inline function instead of a macro:
static inline bool cti_accessible(struct cti_drvdata *drvdata) { struct cti_config *cfg = &drvdata->config;
return cfg->hw_powered && cfg->hw_enabled; }
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;
+ state = " (cached)";
- }
- spin_unlock(&drvdata->spinlock);
- return scnprintf(buf, PAGE_SIZE, "%#x\n", val);
+ return scnprintf(buf, PAGE_SIZE, "%#x%s\n", val, state);
+}
+/*
- 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)
+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*/
nit: a 0b1 ?
- 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);
Otherwise looks good to me.
Suzuki
Hi Suzuki,
On Wed, 27 Nov 2019 at 18:26, Suzuki Kuruppassery Poulose suzuki.poulose@arm.com wrote:
On 19/11/2019 23:19, Mike Leach wrote:
Adds in sysfs programming support for the CTI function register sets. Allows direct manipulation of channel / trigger association registers.
Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-cti-sysfs.c | 362 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.c | 19 + drivers/hwtracing/coresight/coresight-cti.h | 5 + 3 files changed, 386 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 507f8eb487fe..02d3ee0c1278 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -109,6 +109,362 @@ 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.
- */
Also I am not sure if it makes sense to mention that the value is cached.
+static ssize_t cti_reg32_show(struct device *dev, char *buf,
u32 *pcached_val, int reg_offset)
+{
u32 val = 0;
- char *state = "";
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)) {
minor nit: Personally I don't like the naming here. This could simply be: cti_accessible(config) , may be defined as a static inline function instead of a macro:
static inline bool cti_accessible(struct cti_drvdata *drvdata) { struct cti_config *cfg = &drvdata->config;
return cfg->hw_powered && cfg->hw_enabled;
}
Since this is a generic access function used throughout the file - the cached pointer is an indicator used by the callee that there is a value available if the CTI is unpowered / disabled - so the function can show an appropriate value which will be taken from the config structure.
So I don't think it is relevant to show that a "cached" value is being used to show the user. If you look at similar functions in the ETM drivers for example, quite often a show function simple shows that stored value from a config structure without ever looking at the register in the device.
As to naming - the name is chosen to represent a specific state - both powered and enabled. The sysfs interface is accessible in any state - powered / unpowered , enabled /disabled - so I am being specific. Unlike the ETM, this hardware can have registers programmed while enabled - and for some such as apppulse this is the only time it makes sense to use them.
I don't mind either way between macro / inline function - though it still has to be declared in the header as it is used in multiple .c files. I'd be inclined to call it cti_active() if preferred to cti_pwr_ena - active implies that the CTI is in operation.
Thanks
Mike
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;
state = " (cached)";
}
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#x\n", val);
- return scnprintf(buf, PAGE_SIZE, "%#x%s\n", val, state);
+}
+/*
- 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)
+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*/
nit: a 0b1 ?
Syntax is <bitwidth>'<radix><value> - a habit picked up from verilog.
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);
Otherwise looks good to me.
Suzuki
On 19/11/2019 23:19, Mike Leach wrote:
Adds in sysfs programming support for the CTI function register sets. Allows direct manipulation of channel / trigger association registers.
Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org Signed-off-by: Mike Leach mike.leach@linaro.org
+/*
- #define CTI_DEBUG_INTEGRATION_CTRL to enable the access to the integration
- control registers. Normally only used to investigate connection data.
- */
On a second thought, I have some comments on this symbol.
Given that the integration control registers may be useful for people to find the device connections, I strongly feel that this is provided via a CONFIG symbol rather than a debug symbol within the code.
i.e, CONFIG_CTI_DEBUG_INTEGRATION_CTRL, to help the people better. Codewise this doesn't make much difference, but it certainly makes it more easier for people to use it.
We have used debug symbols elsewhere in the drivers for pure functional debugging purposes. However I feel this is case is superior.
Cheers Suzuki
On Thu, 28 Nov 2019 at 03:54, Suzuki Kuruppassery Poulose suzuki.poulose@arm.com wrote:
On 19/11/2019 23:19, Mike Leach wrote:
Adds in sysfs programming support for the CTI function register sets. Allows direct manipulation of channel / trigger association registers.
Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org Signed-off-by: Mike Leach mike.leach@linaro.org
+/*
- #define CTI_DEBUG_INTEGRATION_CTRL to enable the access to the integration
- control registers. Normally only used to investigate connection data.
- */
On a second thought, I have some comments on this symbol.
Given that the integration control registers may be useful for people to find the device connections, I strongly feel that this is provided via a CONFIG symbol rather than a debug symbol within the code.
Device connections can be discovered with the dynamic sysfs connection entries added as part of patch 09. In cases where that is not sufficient and people really need to use the integration control registers they are probably instrumenting the code anyway.
i.e, CONFIG_CTI_DEBUG_INTEGRATION_CTRL, to help the people better. Codewise this doesn't make much difference, but it certainly makes it more easier for people to use it.
I agree that code-wise it doesn't make much difference but I'm really not convinced it makes the driver easier to use, and one needs to recompile their kernel for production systems anyway.
Thanks, Mathieu
We have used debug symbols elsewhere in the drivers for pure functional debugging purposes. However I feel this is case is superior.
Cheers Suzuki
Hi Mathieu,
On 28/11/2019 17:20, Mathieu Poirier wrote:
On Thu, 28 Nov 2019 at 03:54, Suzuki Kuruppassery Poulose suzuki.poulose@arm.com wrote:
On 19/11/2019 23:19, Mike Leach wrote:
Adds in sysfs programming support for the CTI function register sets. Allows direct manipulation of channel / trigger association registers.
Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org Signed-off-by: Mike Leach mike.leach@linaro.org
+/*
- #define CTI_DEBUG_INTEGRATION_CTRL to enable the access to the integration
- control registers. Normally only used to investigate connection data.
- */
On a second thought, I have some comments on this symbol.
Given that the integration control registers may be useful for people to find the device connections, I strongly feel that this is provided via a CONFIG symbol rather than a debug symbol within the code.
Device connections can be discovered with the dynamic sysfs connection entries added as part of patch 09. In cases where that is not
Yes, that correct. That happens only if the DT/ACPI describes the connections.
sufficient and people really need to use the integration control registers they are probably instrumenting the code anyway.
In this case given the CTI number of triggers and connections, this step is to identify the connections in the first place, so that they can be described in the DT/ACPI. Of course this is not a common activity, but more of a board bring up activity. Thus, we can't expect the board bringup engineer to necessarily know how to modify the driver to get this exposed. Having a Kconfig entry, with a help text makes this easier for them to avoid fiddling with the code. Hope this is clearer now.
Cheers Suzuki
i.e, CONFIG_CTI_DEBUG_INTEGRATION_CTRL, to help the people better. Codewise this doesn't make much difference, but it certainly makes it more easier for people to use it.
I agree that code-wise it doesn't make much difference but I'm really not convinced it makes the driver easier to use, and one needs to recompile their kernel for production systems anyway.
Thanks, Mathieu
We have used debug symbols elsewhere in the drivers for pure functional debugging purposes. However I feel this is case is superior.
Cheers Suzuki
Hi Suzuki, Mathieu,
On Thu, 28 Nov 2019 at 10:54, Suzuki Kuruppassery Poulose suzuki.poulose@arm.com wrote:
On 19/11/2019 23:19, Mike Leach wrote:
Adds in sysfs programming support for the CTI function register sets. Allows direct manipulation of channel / trigger association registers.
Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org Signed-off-by: Mike Leach mike.leach@linaro.org
+/*
- #define CTI_DEBUG_INTEGRATION_CTRL to enable the access to the integration
- control registers. Normally only used to investigate connection data.
- */
On a second thought, I have some comments on this symbol.
Given that the integration control registers may be useful for people to find the device connections, I strongly feel that this is provided via a CONFIG symbol rather than a debug symbol within the code.
i.e, CONFIG_CTI_DEBUG_INTEGRATION_CTRL, to help the people better. Codewise this doesn't make much difference, but it certainly makes it more easier for people to use it.
We have used debug symbols elsewhere in the drivers for pure functional debugging purposes. However I feel this is case is superior.
Cheers Suzuki
Per the comment above, and the discussions following, I would agree that using a config symbol makes it easier for users to select the feature and gives us an opportunity to put in some explanation as to what it does.
Thanks
Mike
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 | 349 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.c | 147 ++++++++ drivers/hwtracing/coresight/coresight-cti.h | 32 ++ 3 files changed, 528 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 02d3ee0c1278..98de8a4768fc 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -464,6 +464,349 @@ 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 = -EINVAL; + + /* extract chan idx and trigger idx */ + items = sscanf(buf, "%d %d", &chan_idx, &trig_idx); + if (items == 2) { + err = cti_channel_trig_op(dev, op, dir, chan_idx, trig_idx); + if (!err) + err = size; + } + 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 chan_gate_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int err = 0, channel = 0; + + if (kstrtoint(buf, 0, &channel)) + return -EINVAL; + + err = cti_channel_gate_op(dev, CTI_GATE_CHAN_ENABLE, channel); + return err ? err : size; +} + +static ssize_t chan_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, "\n"); + else + size = bitmap_print_to_pagebuf(true, buf, &ctigate_bitmask, + cfg->nr_ctm_channels); + return size; +} +static DEVICE_ATTR_RW(chan_gate_enable); + +static ssize_t chan_gate_disable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int err = 0, channel = 0; + + 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(chan_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) +{ + u32 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, "%d\n", val); +} + +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); + +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); + return size; +} +static DEVICE_ATTR_RO(trigout_filtered); + +/* clear all xtrigger / channel programming */ +static ssize_t chan_xtrigs_reset_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(chan_xtrigs_reset); + +/* + * Write to select a channel to view, read to display the + * cross triggers for the selected channel. + */ +static ssize_t chan_xtrigs_view_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 ssize_t chan_xtrigs_view_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, "[%d] IN: ", cfg->xtrig_rchan_sel); + 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_RW(chan_xtrigs_view); + +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, "\n"); + return size; +} + +static ssize_t chan_inuse_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return print_chan_list(dev, buf, true); +} +static DEVICE_ATTR_RO(chan_inuse); + +static ssize_t chan_free_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return print_chan_list(dev, buf, false); +} +static DEVICE_ATTR_RO(chan_free); + +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_trig_filter_enable.attr, + &dev_attr_trigout_filtered.attr, + &dev_attr_chan_gate_enable.attr, + &dev_attr_chan_gate_disable.attr, + &dev_attr_chan_set.attr, + &dev_attr_chan_clear.attr, + &dev_attr_chan_pulse.attr, + &dev_attr_chan_inuse.attr, + &dev_attr_chan_free.attr, + &dev_attr_chan_xtrigs_view.attr, + &dev_attr_chan_xtrigs_reset.attr, + NULL, +}; + /* sysfs groups */ static const struct attribute_group coresight_cti_group = { .attrs = coresight_cti_attrs, @@ -479,9 +822,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 b016b1e67fb1..369488dd7b8e 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -293,6 +293,153 @@ 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; + + 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 73869fa8b313..9a22f6fcad65 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -168,6 +168,30 @@ 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, +}; + +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, @@ -180,8 +204,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);
On Tue, Nov 19, 2019 at 11:19:02PM +0000, 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 | 349 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.c | 147 ++++++++ drivers/hwtracing/coresight/coresight-cti.h | 32 ++ 3 files changed, 528 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 02d3ee0c1278..98de8a4768fc 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -464,6 +464,349 @@ 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 = -EINVAL;
- /* extract chan idx and trigger idx */
- items = sscanf(buf, "%d %d", &chan_idx, &trig_idx);
- if (items == 2) {
err = cti_channel_trig_op(dev, op, dir, chan_idx, trig_idx);
if (!err)
err = size;
- }
- 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 chan_gate_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- int err = 0, channel = 0;
- if (kstrtoint(buf, 0, &channel))
return -EINVAL;
- err = cti_channel_gate_op(dev, CTI_GATE_CHAN_ENABLE, channel);
- return err ? err : size;
+}
+static ssize_t chan_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, "\n");
- else
size = bitmap_print_to_pagebuf(true, buf, &ctigate_bitmask,
cfg->nr_ctm_channels);
- return size;
+} +static DEVICE_ATTR_RW(chan_gate_enable);
+static ssize_t chan_gate_disable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- int err = 0, channel = 0;
- 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(chan_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)
+{
- u32 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, "%d\n", val);
+}
+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);
+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);
- return size;
+} +static DEVICE_ATTR_RO(trigout_filtered);
+/* clear all xtrigger / channel programming */ +static ssize_t chan_xtrigs_reset_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(chan_xtrigs_reset);
+/*
- Write to select a channel to view, read to display the
- cross triggers for the selected channel.
- */
+static ssize_t chan_xtrigs_view_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 ssize_t chan_xtrigs_view_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, "[%d] IN: ", cfg->xtrig_rchan_sel);
- 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_RW(chan_xtrigs_view);
+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, "\n");
- return size;
+}
+static ssize_t chan_inuse_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- return print_chan_list(dev, buf, true);
+} +static DEVICE_ATTR_RO(chan_inuse);
+static ssize_t chan_free_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- return print_chan_list(dev, buf, false);
+} +static DEVICE_ATTR_RO(chan_free);
+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_trig_filter_enable.attr,
- &dev_attr_trigout_filtered.attr,
- &dev_attr_chan_gate_enable.attr,
- &dev_attr_chan_gate_disable.attr,
- &dev_attr_chan_set.attr,
- &dev_attr_chan_clear.attr,
- &dev_attr_chan_pulse.attr,
- &dev_attr_chan_inuse.attr,
- &dev_attr_chan_free.attr,
- &dev_attr_chan_xtrigs_view.attr,
- &dev_attr_chan_xtrigs_reset.attr,
- NULL,
+};
/* sysfs groups */ static const struct attribute_group coresight_cti_group = { .attrs = coresight_cti_attrs, @@ -479,9 +822,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 b016b1e67fb1..369488dd7b8e 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -293,6 +293,153 @@ 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;
- 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 73869fa8b313..9a22f6fcad65 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -168,6 +168,30 @@ 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,
+};
+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, @@ -180,8 +204,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);
Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org
2.17.1
On 19/11/2019 23:19, 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
+static ssize_t chan_xtrigs_view_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, "[%d] IN: ", cfg->xtrig_rchan_sel);
- 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);
}
- }
As a security measure, we must make sure that we have space left in the buffer. We could end up passing "negative" numbers for the size argument, in the worst case.
- 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_RW(chan_xtrigs_view);
The rest looks fine to me.
Suzuki
Hi Suzuki,
On Wed, 27 Nov 2019 at 18:40, Suzuki Kuruppassery Poulose suzuki.poulose@arm.com wrote:
On 19/11/2019 23:19, 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
+static ssize_t chan_xtrigs_view_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, "[%d] IN: ", cfg->xtrig_rchan_sel);
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);
}
}
As a security measure, we must make sure that we have space left in the buffer. We could end up passing "negative" numbers for the size argument, in the worst case.
The return value from scnprintf() is always the _actual_ number of characters added to the buffer, not as per snprintf() which returns the number that could have been printed if there were sufficient space. Thus used can never exceed the buffer size.
Regards
Mike
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_RW(chan_xtrigs_view);
The rest looks fine to me.
Suzuki
Adds new coresight-cti.yaml 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-cti.yaml | 303 ++++++++++++++++++ .../devicetree/bindings/arm/coresight.txt | 7 + MAINTAINERS | 2 + include/dt-bindings/arm/coresight-cti-dt.h | 37 +++ 4 files changed, 349 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/coresight-cti.yaml create mode 100644 include/dt-bindings/arm/coresight-cti-dt.h
diff --git a/Documentation/devicetree/bindings/arm/coresight-cti.yaml b/Documentation/devicetree/bindings/arm/coresight-cti.yaml new file mode 100644 index 000000000000..882c72f1c798 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/coresight-cti.yaml @@ -0,0 +1,303 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright 2019 Linaro Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/coresight-cti.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ARM Coresight Cross Trigger Interface (CTI) device. + +description: | + 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. + + 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. + + When only minimal information is available for the CTI trigger connections, + then a minimal driver binding can be declare with no explicit trigger + signals. This will result in the 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. This minimal + binding may be used when using the Integration Control registers to + discover connections between CTI and other CoreSight components, + + Certain triggers between CoreSight devices and the CTI have specific types + and 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. + + Note that some hardware trigger signals can be connected to non-CoreSight + components (e.g. UART etc) depending on hardware implementation. + +maintainers: + - Mike Leach mike.leach@linaro.org + +allOf: + - $ref: /schemas/arm/primecell.yaml# + +# Need a custom select here or 'arm,primecell' will match on lots of nodes +select: + properties: + compatible: + contains: + enum: + - arm,coresight-cti + required: + - compatible + +properties: + $nodename: + pattern: "^cti(@[0-9a-f,]+)*$" + compatible: + items: + - const: arm,coresight-cti + - const: arm,primecell + + reg: + items: + - description: device programming registers + + arm,cti-v8-arch: + type: boolean + description: + This CTI follows the v8 architecturally mandated layout for a CTI. + Bindings declaring this must declare a cpu, and optionally 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. + + cpu: + allOf: + - $ref: /schemas/types.yaml#/definitions/phandle + description: Handle to cpu this device is associated with. + + arm,cti-ctm-id: + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + description: + Defines the CTM this CTI is connected to, in large systems with multiple + separate CTI/CTM nets. Typically multi-socket systems where the CTM is + propagated between sockets. + + arm,cs-dev-assoc: + allOf: + - $ref: /schemas/types.yaml#/definitions/phandle + description: + 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. + +patternProperties: + '^trig_conns@[0-9]+$': + type: object + description: + A trigger connections child node which describes the trigger signals + between this CTI and another hardware device. This device may be a CPU, + CoreSight device, any other hardware device or simple external IO lines. + The connection may have both input and output triggers, or only one or the + other. + + properties: + + arm,trig-in-sigs: + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 32 + description: + List of CTI trigger in signal numbers in use by a trig-conns node. + + arm,trig-in-types: + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 32 + description: + List of constants representing the 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: + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 32 + description: + List of CTI trigger out signal numbers in use by a trig-conns node. + + arm,trig-out-types: + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 32 + description: + List of constants representing the 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: + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 32 + description: + List of CTI trigger out signals that will be blocked from becoming + active, unless filtering is disabled on the driver. + + arm,trig-conn-name: + allOf: + - $ref: /schemas/types.yaml#/definitions/string + description: + Defines a connection name that will be displayed, if the cpu or + arm,cs-dev-assoc properties are not being used in this connection. + Principle use for CTI that are connected to non-CoreSight devices, or + external IO. + + anyOf: + - required: + - arm,trig-in-sigs + - required: + - arm,trig-out-sigs + oneOf: + - required: + - arm,trig-conn-name + - required: + - cpu + - required: + - arm,cs-dev-assoc + +required: + - compatible + - reg + - clocks + - clock-names + +examples: + # minimum CTI definition. DEVID register used to set number of triggers. + - | + cti@20020000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x20020000 0x1000>; + + clocks = <&soc_smc50mhz>; + clock-names = "apb_pclk"; + }; + # v8 architecturally defined CTI - CPU + ETM connections generated by the + # driver according to the v8 architecture specification. + - | + cti@859000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x859000 0x1000>; + + clocks = <&soc_smc50mhz>; + clock-names = "apb_pclk"; + + arm,cti-v8-arch; + cpu = <&CPU1>; + arm,cs-dev-assoc = <&etm1>; + }; + # Implementation defined CTI - CPU + ETM connections explicitly defined.. + # Shows use of type constants from dt-bindings/arm/coresight-cti-dt.h + - | + #include <dt-bindings/arm/coresight-cti-dt.h> + + cti@858000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x858000 0x1000>; + + clocks = <&soc_smc50mhz>; + clock-names = "apb_pclk"; + + arm,cti-ctm-id = <1>; + + 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>; + }; + }; + # Implementation defined CTI - none CoreSight component connections. + - | + cti@20110000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0 0x20110000 0 0x1000>; + + clocks = <&soc_smc50mhz>; + clock-names = "apb_pclk"; + + 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-in-sigs=<1 6>; + arm,trig-in-types=<GEN_HALTREQ GEN_RESTARTREQ>; + arm,trig-conn-name = "g_counter"; + }; + }; + +... \ No newline at end of file diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt index d02c42d21f2f..846f6daae71b 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-cti.yaml 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-cti.yaml 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 9de89d75dbcc..8d01a74068f7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1608,9 +1608,11 @@ 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/* F: Documentation/devicetree/bindings/arm/coresight.txt F: Documentation/devicetree/bindings/arm/coresight-cpu-debug.txt +F: Documentation/devicetree/bindings/arm/coresight-cti.yaml 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..61e7bdf8ea6e --- /dev/null +++ b/include/dt-bindings/arm/coresight-cti-dt.h @@ -0,0 +1,37 @@ +/* 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 +#define CTI_TRIG_MAX 25 + +#endif /*_DT_BINDINGS_ARM_CORESIGHT_CTI_DT_H */
On Tue, Nov 19, 2019 at 11:19:03PM +0000, Mike Leach wrote:
Adds new coresight-cti.yaml 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-cti.yaml | 303 ++++++++++++++++++ .../devicetree/bindings/arm/coresight.txt | 7 + MAINTAINERS | 2 + include/dt-bindings/arm/coresight-cti-dt.h | 37 +++ 4 files changed, 349 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/coresight-cti.yaml create mode 100644 include/dt-bindings/arm/coresight-cti-dt.h
diff --git a/Documentation/devicetree/bindings/arm/coresight-cti.yaml b/Documentation/devicetree/bindings/arm/coresight-cti.yaml new file mode 100644 index 000000000000..882c72f1c798 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/coresight-cti.yaml @@ -0,0 +1,303 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright 2019 Linaro Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/coresight-cti.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml#
+title: ARM Coresight Cross Trigger Interface (CTI) device.
+description: |
- 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.
- 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.
- When only minimal information is available for the CTI trigger connections,
- then a minimal driver binding can be declare with no explicit trigger
- signals. This will result in the 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. This minimal
- binding may be used when using the Integration Control registers to
- discover connections between CTI and other CoreSight components,
- Certain triggers between CoreSight devices and the CTI have specific types
- and 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.
- Note that some hardware trigger signals can be connected to non-CoreSight
- components (e.g. UART etc) depending on hardware implementation.
+maintainers:
- Mike Leach mike.leach@linaro.org
+allOf:
- $ref: /schemas/arm/primecell.yaml#
+# Need a custom select here or 'arm,primecell' will match on lots of nodes +select:
- properties:
- compatible:
contains:
enum:
- arm,coresight-cti
- required:
- compatible
+properties:
- $nodename:
- pattern: "^cti(@[0-9a-f,]+)*$"
- compatible:
- items:
- const: arm,coresight-cti
- const: arm,primecell
- reg:
- items:
- description: device programming registers
- arm,cti-v8-arch:
- type: boolean
- description:
This CTI follows the v8 architecturally mandated layout for a CTI.
Bindings declaring this must declare a cpu, and optionally 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.
- cpu:
- allOf:
- $ref: /schemas/types.yaml#/definitions/phandle
- description: Handle to cpu this device is associated with.
- arm,cti-ctm-id:
- allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- description:
Defines the CTM this CTI is connected to, in large systems with multiple
separate CTI/CTM nets. Typically multi-socket systems where the CTM is
propagated between sockets.
- arm,cs-dev-assoc:
- allOf:
- $ref: /schemas/types.yaml#/definitions/phandle
- description:
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.
+patternProperties:
- '^trig_conns@[0-9]+$':
- type: object
- description:
A trigger connections child node which describes the trigger signals
between this CTI and another hardware device. This device may be a CPU,
CoreSight device, any other hardware device or simple external IO lines.
The connection may have both input and output triggers, or only one or the
other.
- properties:
arm,trig-in-sigs:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of CTI trigger in signal numbers in use by a trig-conns node.
arm,trig-in-types:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of constants representing the 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:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of CTI trigger out signal numbers in use by a trig-conns node.
arm,trig-out-types:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of constants representing the 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:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of CTI trigger out signals that will be blocked from becoming
active, unless filtering is disabled on the driver.
arm,trig-conn-name:
allOf:
- $ref: /schemas/types.yaml#/definitions/string
description:
Defines a connection name that will be displayed, if the cpu or
arm,cs-dev-assoc properties are not being used in this connection.
Principle use for CTI that are connected to non-CoreSight devices, or
external IO.
- anyOf:
- required:
- arm,trig-in-sigs
- required:
- arm,trig-out-sigs
- oneOf:
- required:
- arm,trig-conn-name
- required:
- cpu
- required:
- arm,cs-dev-assoc
+required:
- compatible
- reg
- clocks
- clock-names
+examples:
- # minimum CTI definition. DEVID register used to set number of triggers.
- |
- cti@20020000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x20020000 0x1000>;
clocks = <&soc_smc50mhz>;
clock-names = "apb_pclk";
- };
- # v8 architecturally defined CTI - CPU + ETM connections generated by the
- # driver according to the v8 architecture specification.
- |
- cti@859000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x859000 0x1000>;
clocks = <&soc_smc50mhz>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&CPU1>;
arm,cs-dev-assoc = <&etm1>;
- };
- # Implementation defined CTI - CPU + ETM connections explicitly defined..
- # Shows use of type constants from dt-bindings/arm/coresight-cti-dt.h
- |
- #include <dt-bindings/arm/coresight-cti-dt.h>
- cti@858000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x858000 0x1000>;
clocks = <&soc_smc50mhz>;
clock-names = "apb_pclk";
arm,cti-ctm-id = <1>;
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>;
};
- };
- # Implementation defined CTI - none CoreSight component connections.
- |
- cti@20110000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0 0x20110000 0 0x1000>;
clocks = <&soc_smc50mhz>;
clock-names = "apb_pclk";
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-in-sigs=<1 6>;
arm,trig-in-types=<GEN_HALTREQ GEN_RESTARTREQ>;
arm,trig-conn-name = "g_counter";
};
- };
+...
I'm not sure what the "..." is there for. It is not present in the example schema[1] but I can find the patter in other .yaml files. As such I will let Rob decide on that part.
Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org
[1]. Documentation/devicetree/bindings/example-schema.yaml
\ No newline at end of file diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt index d02c42d21f2f..846f6daae71b 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-cti.yaml 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-cti.yaml 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 9de89d75dbcc..8d01a74068f7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1608,9 +1608,11 @@ 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/* F: Documentation/devicetree/bindings/arm/coresight.txt F: Documentation/devicetree/bindings/arm/coresight-cpu-debug.txt +F: Documentation/devicetree/bindings/arm/coresight-cti.yaml 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..61e7bdf8ea6e --- /dev/null +++ b/include/dt-bindings/arm/coresight-cti-dt.h @@ -0,0 +1,37 @@ +/* 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 +#define CTI_TRIG_MAX 25
+#endif /*_DT_BINDINGS_ARM_CORESIGHT_CTI_DT_H */
2.17.1
Hi Mathieu,
... is an optional end of document marker in YAML. Seemed to appear in most of the files I looked at in the devicetree.org dt-schema project I looked at so I took it as customary for DT YAML docs. But as you say - it's up to Rob etc. to approve or otherwise.
Regards
Mike
On Wed, 20 Nov 2019 at 19:06, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Tue, Nov 19, 2019 at 11:19:03PM +0000, Mike Leach wrote:
Adds new coresight-cti.yaml 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-cti.yaml | 303 ++++++++++++++++++ .../devicetree/bindings/arm/coresight.txt | 7 + MAINTAINERS | 2 + include/dt-bindings/arm/coresight-cti-dt.h | 37 +++ 4 files changed, 349 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/coresight-cti.yaml create mode 100644 include/dt-bindings/arm/coresight-cti-dt.h
diff --git a/Documentation/devicetree/bindings/arm/coresight-cti.yaml b/Documentation/devicetree/bindings/arm/coresight-cti.yaml new file mode 100644 index 000000000000..882c72f1c798 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/coresight-cti.yaml @@ -0,0 +1,303 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright 2019 Linaro Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/coresight-cti.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml#
+title: ARM Coresight Cross Trigger Interface (CTI) device.
+description: |
- 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.
- 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.
- When only minimal information is available for the CTI trigger connections,
- then a minimal driver binding can be declare with no explicit trigger
- signals. This will result in the 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. This minimal
- binding may be used when using the Integration Control registers to
- discover connections between CTI and other CoreSight components,
- Certain triggers between CoreSight devices and the CTI have specific types
- and 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.
- Note that some hardware trigger signals can be connected to non-CoreSight
- components (e.g. UART etc) depending on hardware implementation.
+maintainers:
- Mike Leach mike.leach@linaro.org
+allOf:
- $ref: /schemas/arm/primecell.yaml#
+# Need a custom select here or 'arm,primecell' will match on lots of nodes +select:
- properties:
- compatible:
contains:
enum:
- arm,coresight-cti
- required:
- compatible
+properties:
- $nodename:
- pattern: "^cti(@[0-9a-f,]+)*$"
- compatible:
- items:
- const: arm,coresight-cti
- const: arm,primecell
- reg:
- items:
- description: device programming registers
- arm,cti-v8-arch:
- type: boolean
- description:
This CTI follows the v8 architecturally mandated layout for a CTI.
Bindings declaring this must declare a cpu, and optionally 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.
- cpu:
- allOf:
- $ref: /schemas/types.yaml#/definitions/phandle
- description: Handle to cpu this device is associated with.
- arm,cti-ctm-id:
- allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- description:
Defines the CTM this CTI is connected to, in large systems with multiple
separate CTI/CTM nets. Typically multi-socket systems where the CTM is
propagated between sockets.
- arm,cs-dev-assoc:
- allOf:
- $ref: /schemas/types.yaml#/definitions/phandle
- description:
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.
+patternProperties:
- '^trig_conns@[0-9]+$':
- type: object
- description:
A trigger connections child node which describes the trigger signals
between this CTI and another hardware device. This device may be a CPU,
CoreSight device, any other hardware device or simple external IO lines.
The connection may have both input and output triggers, or only one or the
other.
- properties:
arm,trig-in-sigs:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of CTI trigger in signal numbers in use by a trig-conns node.
arm,trig-in-types:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of constants representing the 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:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of CTI trigger out signal numbers in use by a trig-conns node.
arm,trig-out-types:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of constants representing the 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:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of CTI trigger out signals that will be blocked from becoming
active, unless filtering is disabled on the driver.
arm,trig-conn-name:
allOf:
- $ref: /schemas/types.yaml#/definitions/string
description:
Defines a connection name that will be displayed, if the cpu or
arm,cs-dev-assoc properties are not being used in this connection.
Principle use for CTI that are connected to non-CoreSight devices, or
external IO.
- anyOf:
- required:
- arm,trig-in-sigs
- required:
- arm,trig-out-sigs
- oneOf:
- required:
- arm,trig-conn-name
- required:
- cpu
- required:
- arm,cs-dev-assoc
+required:
- compatible
- reg
- clocks
- clock-names
+examples:
- # minimum CTI definition. DEVID register used to set number of triggers.
- |
- cti@20020000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x20020000 0x1000>;
clocks = <&soc_smc50mhz>;
clock-names = "apb_pclk";
- };
- # v8 architecturally defined CTI - CPU + ETM connections generated by the
- # driver according to the v8 architecture specification.
- |
- cti@859000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x859000 0x1000>;
clocks = <&soc_smc50mhz>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&CPU1>;
arm,cs-dev-assoc = <&etm1>;
- };
- # Implementation defined CTI - CPU + ETM connections explicitly defined..
- # Shows use of type constants from dt-bindings/arm/coresight-cti-dt.h
- |
- #include <dt-bindings/arm/coresight-cti-dt.h>
- cti@858000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x858000 0x1000>;
clocks = <&soc_smc50mhz>;
clock-names = "apb_pclk";
arm,cti-ctm-id = <1>;
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>;
};
- };
- # Implementation defined CTI - none CoreSight component connections.
- |
- cti@20110000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0 0x20110000 0 0x1000>;
clocks = <&soc_smc50mhz>;
clock-names = "apb_pclk";
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-in-sigs=<1 6>;
arm,trig-in-types=<GEN_HALTREQ GEN_RESTARTREQ>;
arm,trig-conn-name = "g_counter";
};
- };
+...
I'm not sure what the "..." is there for. It is not present in the example schema[1] but I can find the patter in other .yaml files. As such I will let Rob decide on that part.
Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org
[1]. Documentation/devicetree/bindings/example-schema.yaml
\ No newline at end of file diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt index d02c42d21f2f..846f6daae71b 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-cti.yaml 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-cti.yaml 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 9de89d75dbcc..8d01a74068f7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1608,9 +1608,11 @@ 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/* F: Documentation/devicetree/bindings/arm/coresight.txt F: Documentation/devicetree/bindings/arm/coresight-cpu-debug.txt +F: Documentation/devicetree/bindings/arm/coresight-cti.yaml 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..61e7bdf8ea6e --- /dev/null +++ b/include/dt-bindings/arm/coresight-cti-dt.h @@ -0,0 +1,37 @@ +/* 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 +#define CTI_TRIG_MAX 25
+#endif /*_DT_BINDINGS_ARM_CORESIGHT_CTI_DT_H */
2.17.1
On Tue, Nov 19, 2019 at 11:19:03PM +0000, Mike Leach wrote:
Adds new coresight-cti.yaml 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-cti.yaml | 303 ++++++++++++++++++ .../devicetree/bindings/arm/coresight.txt | 7 + MAINTAINERS | 2 + include/dt-bindings/arm/coresight-cti-dt.h | 37 +++ 4 files changed, 349 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/coresight-cti.yaml create mode 100644 include/dt-bindings/arm/coresight-cti-dt.h
diff --git a/Documentation/devicetree/bindings/arm/coresight-cti.yaml b/Documentation/devicetree/bindings/arm/coresight-cti.yaml new file mode 100644 index 000000000000..882c72f1c798 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/coresight-cti.yaml @@ -0,0 +1,303 @@ +# SPDX-License-Identifier: GPL-2.0
Dual license new bindings please:
(GPL-2.0-only OR BSD-2-Clause)
+# Copyright 2019 Linaro Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/coresight-cti.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml#
+title: ARM Coresight Cross Trigger Interface (CTI) device.
+description: |
- 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.
- 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.
- When only minimal information is available for the CTI trigger connections,
- then a minimal driver binding can be declare with no explicit trigger
- signals. This will result in the 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. This minimal
- binding may be used when using the Integration Control registers to
- discover connections between CTI and other CoreSight components,
- Certain triggers between CoreSight devices and the CTI have specific types
- and 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.
- Note that some hardware trigger signals can be connected to non-CoreSight
- components (e.g. UART etc) depending on hardware implementation.
+maintainers:
- Mike Leach mike.leach@linaro.org
+allOf:
- $ref: /schemas/arm/primecell.yaml#
+# Need a custom select here or 'arm,primecell' will match on lots of nodes +select:
- properties:
- compatible:
contains:
enum:
- arm,coresight-cti
- required:
- compatible
+properties:
- $nodename:
- pattern: "^cti(@[0-9a-f,]+)*$"
Unit address should not be optional nor have a comma.
- compatible:
- items:
- const: arm,coresight-cti
- const: arm,primecell
- reg:
- items:
- description: device programming registers
Just "maxItems: 1" is sufficient.
- arm,cti-v8-arch:
- type: boolean
- description:
This CTI follows the v8 architecturally mandated layout for a CTI.
Seems like the compatible or primecell ID registers should be used for something like this.
Bindings declaring this must declare a cpu, and optionally 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.
- cpu:
- allOf:
- $ref: /schemas/types.yaml#/definitions/phandle
- description: Handle to cpu this device is associated with.
- arm,cti-ctm-id:
- allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- description:
Defines the CTM this CTI is connected to, in large systems with multiple
separate CTI/CTM nets. Typically multi-socket systems where the CTM is
propagated between sockets.
- arm,cs-dev-assoc:
- allOf:
- $ref: /schemas/types.yaml#/definitions/phandle
- description:
defines a phandle reference to an associated CoreSight trace device.
s/defines/Defines/
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.
+patternProperties:
- '^trig_conns@[0-9]+$':
trig-conns@...
- type: object
- description:
A trigger connections child node which describes the trigger signals
between this CTI and another hardware device. This device may be a CPU,
CoreSight device, any other hardware device or simple external IO lines.
The connection may have both input and output triggers, or only one or the
other.
- properties:
arm,trig-in-sigs:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of CTI trigger in signal numbers in use by a trig-conns node.
arm,trig-in-types:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of constants representing the 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:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of CTI trigger out signal numbers in use by a trig-conns node.
arm,trig-out-types:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of constants representing the 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:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of CTI trigger out signals that will be blocked from becoming
active, unless filtering is disabled on the driver.
arm,trig-conn-name:
allOf:
- $ref: /schemas/types.yaml#/definitions/string
description:
Defines a connection name that will be displayed, if the cpu or
arm,cs-dev-assoc properties are not being used in this connection.
Principle use for CTI that are connected to non-CoreSight devices, or
external IO.
- anyOf:
- required:
- arm,trig-in-sigs
- required:
- arm,trig-out-sigs
- oneOf:
- required:
- arm,trig-conn-name
- required:
- cpu
- required:
- arm,cs-dev-assoc
+required:
- compatible
- reg
- clocks
- clock-names
+examples:
- # minimum CTI definition. DEVID register used to set number of triggers.
- |
- cti@20020000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x20020000 0x1000>;
clocks = <&soc_smc50mhz>;
clock-names = "apb_pclk";
- };
- # v8 architecturally defined CTI - CPU + ETM connections generated by the
- # driver according to the v8 architecture specification.
- |
- cti@859000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x859000 0x1000>;
clocks = <&soc_smc50mhz>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&CPU1>;
arm,cs-dev-assoc = <&etm1>;
- };
- # Implementation defined CTI - CPU + ETM connections explicitly defined..
- # Shows use of type constants from dt-bindings/arm/coresight-cti-dt.h
- |
- #include <dt-bindings/arm/coresight-cti-dt.h>
- cti@858000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x858000 0x1000>;
clocks = <&soc_smc50mhz>;
clock-names = "apb_pclk";
arm,cti-ctm-id = <1>;
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>;
};
- };
- # Implementation defined CTI - none CoreSight component connections.
- |
- cti@20110000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0 0x20110000 0 0x1000>;
clocks = <&soc_smc50mhz>;
clock-names = "apb_pclk";
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-in-sigs=<1 6>;
arm,trig-in-types=<GEN_HALTREQ GEN_RESTARTREQ>;
arm,trig-conn-name = "g_counter";
};
- };
+... \ No newline at end of file
'...' is preferred, but the fix the lack of newline.
diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt index d02c42d21f2f..846f6daae71b 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-cti.yaml 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-cti.yaml 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 9de89d75dbcc..8d01a74068f7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1608,9 +1608,11 @@ 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/* F: Documentation/devicetree/bindings/arm/coresight.txt F: Documentation/devicetree/bindings/arm/coresight-cpu-debug.txt +F: Documentation/devicetree/bindings/arm/coresight-cti.yaml 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..61e7bdf8ea6e --- /dev/null +++ b/include/dt-bindings/arm/coresight-cti-dt.h @@ -0,0 +1,37 @@ +/* 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 +#define CTI_TRIG_MAX 25
+#endif /*_DT_BINDINGS_ARM_CORESIGHT_CTI_DT_H */
2.17.1
Hi Rob,
On Fri, 22 Nov 2019 at 23:33, Rob Herring robh@kernel.org wrote:
On Tue, Nov 19, 2019 at 11:19:03PM +0000, Mike Leach wrote:
Adds new coresight-cti.yaml 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-cti.yaml | 303 ++++++++++++++++++ .../devicetree/bindings/arm/coresight.txt | 7 + MAINTAINERS | 2 + include/dt-bindings/arm/coresight-cti-dt.h | 37 +++ 4 files changed, 349 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/coresight-cti.yaml create mode 100644 include/dt-bindings/arm/coresight-cti-dt.h
diff --git a/Documentation/devicetree/bindings/arm/coresight-cti.yaml b/Documentation/devicetree/bindings/arm/coresight-cti.yaml new file mode 100644 index 000000000000..882c72f1c798 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/coresight-cti.yaml @@ -0,0 +1,303 @@ +# SPDX-License-Identifier: GPL-2.0
Dual license new bindings please:
(GPL-2.0-only OR BSD-2-Clause)
OK.
+# Copyright 2019 Linaro Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/coresight-cti.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml#
+title: ARM Coresight Cross Trigger Interface (CTI) device.
+description: |
- 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.
- 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.
- When only minimal information is available for the CTI trigger connections,
- then a minimal driver binding can be declare with no explicit trigger
- signals. This will result in the 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. This minimal
- binding may be used when using the Integration Control registers to
- discover connections between CTI and other CoreSight components,
- Certain triggers between CoreSight devices and the CTI have specific types
- and 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.
- Note that some hardware trigger signals can be connected to non-CoreSight
- components (e.g. UART etc) depending on hardware implementation.
+maintainers:
- Mike Leach mike.leach@linaro.org
+allOf:
- $ref: /schemas/arm/primecell.yaml#
+# Need a custom select here or 'arm,primecell' will match on lots of nodes +select:
- properties:
- compatible:
contains:
enum:
- arm,coresight-cti
- required:
- compatible
+properties:
- $nodename:
- pattern: "^cti(@[0-9a-f,]+)*$"
Unit address should not be optional nor have a comma.
Will fix.
- compatible:
- items:
- const: arm,coresight-cti
- const: arm,primecell
- reg:
- items:
- description: device programming registers
Just "maxItems: 1" is sufficient.
OK
- arm,cti-v8-arch:
- type: boolean
- description:
This CTI follows the v8 architecturally mandated layout for a CTI.
Seems like the compatible or primecell ID registers should be used for something like this.
Unfortunately it is possible and has happened that the same primecell regs for a CTI connected to a v8 core and one that is used as a general system CTI appear in the same system. There is no architectural requirement on the CTI to indicate that its external connections are as per v8 architecture spec when connected to a PE/ETM combo.
Therefore a compatible "arm,coresight-cti-v8" would seem the best route. I'll update the compatible portion of the schema and handling code accordingly.
Bindings declaring this must declare a cpu, and optionally 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.
- cpu:
- allOf:
- $ref: /schemas/types.yaml#/definitions/phandle
- description: Handle to cpu this device is associated with.
- arm,cti-ctm-id:
- allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- description:
Defines the CTM this CTI is connected to, in large systems with multiple
separate CTI/CTM nets. Typically multi-socket systems where the CTM is
propagated between sockets.
- arm,cs-dev-assoc:
- allOf:
- $ref: /schemas/types.yaml#/definitions/phandle
- description:
defines a phandle reference to an associated CoreSight trace device.
s/defines/Defines/
OK
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.
+patternProperties:
- '^trig_conns@[0-9]+$':
trig-conns@...
will fix.
- type: object
- description:
A trigger connections child node which describes the trigger signals
between this CTI and another hardware device. This device may be a CPU,
CoreSight device, any other hardware device or simple external IO lines.
The connection may have both input and output triggers, or only one or the
other.
- properties:
arm,trig-in-sigs:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of CTI trigger in signal numbers in use by a trig-conns node.
arm,trig-in-types:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of constants representing the 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:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of CTI trigger out signal numbers in use by a trig-conns node.
arm,trig-out-types:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of constants representing the 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:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of CTI trigger out signals that will be blocked from becoming
active, unless filtering is disabled on the driver.
arm,trig-conn-name:
allOf:
- $ref: /schemas/types.yaml#/definitions/string
description:
Defines a connection name that will be displayed, if the cpu or
arm,cs-dev-assoc properties are not being used in this connection.
Principle use for CTI that are connected to non-CoreSight devices, or
external IO.
- anyOf:
- required:
- arm,trig-in-sigs
- required:
- arm,trig-out-sigs
- oneOf:
- required:
- arm,trig-conn-name
- required:
- cpu
- required:
- arm,cs-dev-assoc
+required:
- compatible
- reg
- clocks
- clock-names
+examples:
- # minimum CTI definition. DEVID register used to set number of triggers.
- |
- cti@20020000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x20020000 0x1000>;
clocks = <&soc_smc50mhz>;
clock-names = "apb_pclk";
- };
- # v8 architecturally defined CTI - CPU + ETM connections generated by the
- # driver according to the v8 architecture specification.
- |
- cti@859000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x859000 0x1000>;
clocks = <&soc_smc50mhz>;
clock-names = "apb_pclk";
arm,cti-v8-arch;
cpu = <&CPU1>;
arm,cs-dev-assoc = <&etm1>;
- };
- # Implementation defined CTI - CPU + ETM connections explicitly defined..
- # Shows use of type constants from dt-bindings/arm/coresight-cti-dt.h
- |
- #include <dt-bindings/arm/coresight-cti-dt.h>
- cti@858000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x858000 0x1000>;
clocks = <&soc_smc50mhz>;
clock-names = "apb_pclk";
arm,cti-ctm-id = <1>;
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>;
};
- };
- # Implementation defined CTI - none CoreSight component connections.
- |
- cti@20110000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0 0x20110000 0 0x1000>;
clocks = <&soc_smc50mhz>;
clock-names = "apb_pclk";
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-in-sigs=<1 6>;
arm,trig-in-types=<GEN_HALTREQ GEN_RESTARTREQ>;
arm,trig-conn-name = "g_counter";
};
- };
+... \ No newline at end of file
'...' is preferred, but the fix the lack of newline.
Will do.
Thanks for the feedback.
Mike
diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt index d02c42d21f2f..846f6daae71b 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-cti.yaml 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-cti.yaml 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 9de89d75dbcc..8d01a74068f7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1608,9 +1608,11 @@ 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/* F: Documentation/devicetree/bindings/arm/coresight.txt F: Documentation/devicetree/bindings/arm/coresight-cpu-debug.txt +F: Documentation/devicetree/bindings/arm/coresight-cti.yaml 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..61e7bdf8ea6e --- /dev/null +++ b/include/dt-bindings/arm/coresight-cti-dt.h @@ -0,0 +1,37 @@ +/* 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 +#define CTI_TRIG_MAX 25
+#endif /*_DT_BINDINGS_ARM_CORESIGHT_CTI_DT_H */
2.17.1
On 29/11/2019 13:50, Mike Leach wrote:
Hi Rob,
On Fri, 22 Nov 2019 at 23:33, Rob Herring robh@kernel.org wrote:
On Tue, Nov 19, 2019 at 11:19:03PM +0000, Mike Leach wrote:
Adds new coresight-cti.yaml 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-cti.yaml | 303 ++++++++++++++++++ .../devicetree/bindings/arm/coresight.txt | 7 + MAINTAINERS | 2 + include/dt-bindings/arm/coresight-cti-dt.h | 37 +++ 4 files changed, 349 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/coresight-cti.yaml create mode 100644 include/dt-bindings/arm/coresight-cti-dt.h
diff --git a/Documentation/devicetree/bindings/arm/coresight-cti.yaml b/Documentation/devicetree/bindings/arm/coresight-cti.yaml new file mode 100644 index 000000000000..882c72f1c798 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/coresight-cti.yaml @@ -0,0 +1,303 @@ +# SPDX-License-Identifier: GPL-2.0
Dual license new bindings please:
(GPL-2.0-only OR BSD-2-Clause)
OK.
+# Copyright 2019 Linaro Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/coresight-cti.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml#
+title: ARM Coresight Cross Trigger Interface (CTI) device.
+description: |
- 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.
- 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.
- When only minimal information is available for the CTI trigger connections,
- then a minimal driver binding can be declare with no explicit trigger
- signals. This will result in the 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. This minimal
- binding may be used when using the Integration Control registers to
- discover connections between CTI and other CoreSight components,
- Certain triggers between CoreSight devices and the CTI have specific types
- and 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.
- Note that some hardware trigger signals can be connected to non-CoreSight
- components (e.g. UART etc) depending on hardware implementation.
+maintainers:
- Mike Leach mike.leach@linaro.org
+allOf:
- $ref: /schemas/arm/primecell.yaml#
+# Need a custom select here or 'arm,primecell' will match on lots of nodes +select:
- properties:
- compatible:
contains:
enum:
- arm,coresight-cti
- required:
- compatible
+properties:
- $nodename:
- pattern: "^cti(@[0-9a-f,]+)*$"
Unit address should not be optional nor have a comma.
Will fix.
- compatible:
- items:
- const: arm,coresight-cti
- const: arm,primecell
- reg:
- items:
- description: device programming registers
Just "maxItems: 1" is sufficient.
OK
- arm,cti-v8-arch:
- type: boolean
- description:
This CTI follows the v8 architecturally mandated layout for a CTI.
Seems like the compatible or primecell ID registers should be used for something like this.
Unfortunately it is possible and has happened that the same primecell regs for a CTI connected to a v8 core and one that is used as a general system CTI appear in the same system. There is no architectural requirement on the CTI to indicate that its external connections are as per v8 architecture spec when connected to a PE/ETM combo.
Therefore a compatible "arm,coresight-cti-v8" would seem the best route. I'll update the compatible portion of the schema and handling code accordingly.
Looks sensible to me. However, please be aware that the coresight devices are triggered via the AMBA bus probe. So, you may have to scan the list of compatibles for this device to figure out, if this is really v8-compatble.
Cheers Suzuki
Hi Mike,
On 19/11/2019 23:19, Mike Leach wrote:
Adds new coresight-cti.yaml 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.
The documentation looks really nice and helpful. Some very minor nits below.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../bindings/arm/coresight-cti.yaml | 303 ++++++++++++++++++ .../devicetree/bindings/arm/coresight.txt | 7 + MAINTAINERS | 2 + include/dt-bindings/arm/coresight-cti-dt.h | 37 +++ 4 files changed, 349 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/coresight-cti.yaml create mode 100644 include/dt-bindings/arm/coresight-cti-dt.h
diff --git a/Documentation/devicetree/bindings/arm/coresight-cti.yaml b/Documentation/devicetree/bindings/arm/coresight-cti.yaml new file mode 100644 index 000000000000..882c72f1c798 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/coresight-cti.yaml @@ -0,0 +1,303 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright 2019 Linaro Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/coresight-cti.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml#
+title: ARM Coresight Cross Trigger Interface (CTI) device.
+description: |
- 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
nit: CTM is not expanded anywhere here. For the sake of completeness, you may do that here.
i.e, s/"a start topology via the CTM"/"a start topology via the Cross Trigger Matrix (CTM)"/
- 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.
- CTIs are interconnected in a star topology via the CTM, using a number of
- programmable channels usually 4, but again implementation defined and
nit: "programmable channels, usually 4, but..." ?
- 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.
nite: are implementation defined, *except when they are connected to an Arm v8 compatible CPU or an ETM* ?
- The v8 architecture defines the required signal connections between CPU core
nit: "The Arm v8"
- and CTI, and ETM and CTI, if the ETM if present.
- When only minimal information is available for the CTI trigger connections,
- then a minimal driver binding can be declare with no explicit trigger
- signals. This will result in the 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. This minimal
- binding may be used when using the Integration Control registers to
- discover connections between CTI and other CoreSight components,
How about "When the CTI trigger connection information is unavailable, the driver detects the number of triggers and channels from the DEVID register and makes them available. The Integration Control registers can be then used to discover the connections for this CTI device to other CoreSight components".
Since we recommend the use of the "Integration Control registers", which is not normally available unless you play around the code, it will be a good idea to metion, what the user needs to do to make the registers available. (One more reason to use the CONFIG symbol, makes that easier.)
- Certain triggers between CoreSight devices and the CTI have specific types
- and 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.
- Note that some hardware trigger signals can be connected to non-CoreSight
- components (e.g. UART etc) depending on hardware implementation.
+maintainers:
- Mike Leach mike.leach@linaro.org
+allOf:
- $ref: /schemas/arm/primecell.yaml#
+# Need a custom select here or 'arm,primecell' will match on lots of nodes +select:
- properties:
- compatible:
contains:
enum:
- arm,coresight-cti
- required:
- compatible
+properties:
- $nodename:
- pattern: "^cti(@[0-9a-f,]+)*$"
- compatible:
- items:
- const: arm,coresight-cti
- const: arm,primecell
- reg:
- items:
- description: device programming registers
- arm,cti-v8-arch:
If possible, please could we make this :
"arm,cti-arm-v8-architected"
to be more meaning ful ?
- type: boolean
- description:
This CTI follows the v8 architecturally mandated layout for a CTI.
Bindings declaring this must declare a cpu, and optionally 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.
- cpu:
- allOf:
- $ref: /schemas/types.yaml#/definitions/phandle
- description: Handle to cpu this device is associated with.
- arm,cti-ctm-id:
- allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- description:
Defines the CTM this CTI is connected to, in large systems with multiple
separate CTI/CTM nets. Typically multi-socket systems where the CTM is
propagated between sockets.
- arm,cs-dev-assoc:
- allOf:
- $ref: /schemas/types.yaml#/definitions/phandle
- description:
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.
+patternProperties:
- '^trig_conns@[0-9]+$':
I understand these bindings have been around for quite long and is too late to make any changes. So, feel free to ignore this suggestion below and I am perfectly fine with it.
--- Begin silly comments Or Skip to DONE ----
Could we make the property names a bit more obvious ? Since they are supposed to be written by other people (unlike our variable names), it always makes sense to have expanded, meaningful names:
s/trig_conns@/triggers@ ?
s/arm,trig-{in,out}-sigs/arm,cti-{in,out}-triggers s/arm,trig-{in,out}-types/arm,cti-{in,out}-trigger-types
"arm,trig-xxx" property name doesn't really imply that it is for cti. So, the above changes makes it explicit and more reader friendly.
- type: object
- description:
A trigger connections child node which describes the trigger signals
between this CTI and another hardware device. This device may be a CPU,
CoreSight device, any other hardware device or simple external IO lines.
The connection may have both input and output triggers, or only one or the
other.
- properties:
arm,trig-in-sigs:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of CTI trigger in signal numbers in use by a trig-conns node.
arm,trig-in-types:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of constants representing the 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:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of CTI trigger out signal numbers in use by a trig-conns node.
arm,trig-out-types:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of constants representing the 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:
arm,cti-trigger-filters ?
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of CTI trigger out signals that will be blocked from becoming
active, unless filtering is disabled on the driver.
arm,trig-conn-name:
arm,cti-trigger-name ?
--- DONE or End of silly comments ---
- # Implementation defined CTI - CPU + ETM connections explicitly defined..
- # Shows use of type constants from dt-bindings/arm/coresight-cti-dt.h
- |
- #include <dt-bindings/arm/coresight-cti-dt.h>
- cti@858000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x858000 0x1000>;
clocks = <&soc_smc50mhz>;
clock-names = "apb_pclk";
arm,cti-ctm-id = <1>;
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>;
};
- };
- # Implementation defined CTI - none CoreSight component connections.
nit: s/none/non ?
Rest looks fine to me.
Suzuki
Hi Suzuki,
On Thu, 28 Nov 2019 at 18:38, Suzuki Kuruppassery Poulose suzuki.poulose@arm.com wrote:
Hi Mike,
On 19/11/2019 23:19, Mike Leach wrote:
Adds new coresight-cti.yaml 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.
The documentation looks really nice and helpful. Some very minor nits below.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../bindings/arm/coresight-cti.yaml | 303 ++++++++++++++++++ .../devicetree/bindings/arm/coresight.txt | 7 + MAINTAINERS | 2 + include/dt-bindings/arm/coresight-cti-dt.h | 37 +++ 4 files changed, 349 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/coresight-cti.yaml create mode 100644 include/dt-bindings/arm/coresight-cti-dt.h
diff --git a/Documentation/devicetree/bindings/arm/coresight-cti.yaml b/Documentation/devicetree/bindings/arm/coresight-cti.yaml new file mode 100644 index 000000000000..882c72f1c798 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/coresight-cti.yaml @@ -0,0 +1,303 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright 2019 Linaro Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/coresight-cti.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml#
+title: ARM Coresight Cross Trigger Interface (CTI) device.
+description: |
- 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
nit: CTM is not expanded anywhere here. For the sake of completeness, you may do that here.
i.e, s/"a start topology via the CTM"/"a start topology via the Cross Trigger Matrix (CTM)"/
Agreed - I think the expansion got lost in the many re-arrangement of this doc.
- 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.
- CTIs are interconnected in a star topology via the CTM, using a number of
- programmable channels usually 4, but again implementation defined and
nit: "programmable channels, usually 4, but..." ?
OK
- 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.
nite: are implementation defined, *except when they are connected to an Arm v8 compatible CPU or an ETM* ?
Agreed - clearer.
- The v8 architecture defines the required signal connections between CPU core
nit: "The Arm v8"
- and CTI, and ETM and CTI, if the ETM if present.
- When only minimal information is available for the CTI trigger connections,
- then a minimal driver binding can be declare with no explicit trigger
- signals. This will result in the 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. This minimal
- binding may be used when using the Integration Control registers to
- discover connections between CTI and other CoreSight components,
How about "When the CTI trigger connection information is unavailable, the driver detects the number of triggers and channels from the DEVID register and makes them available. The Integration Control registers can be then used to discover the connections for this CTI device to other CoreSight components".
Since we recommend the use of the "Integration Control registers", which is not normally available unless you play around the code, it will be a good idea to metion, what the user needs to do to make the registers available. (One more reason to use the CONFIG symbol, makes that easier.)
Agreed - need to explain the use case for this and implications of using a minimal binding.
- Certain triggers between CoreSight devices and the CTI have specific types
- and 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.
- Note that some hardware trigger signals can be connected to non-CoreSight
- components (e.g. UART etc) depending on hardware implementation.
+maintainers:
- Mike Leach mike.leach@linaro.org
+allOf:
- $ref: /schemas/arm/primecell.yaml#
+# Need a custom select here or 'arm,primecell' will match on lots of nodes +select:
- properties:
- compatible:
contains:
enum:
- arm,coresight-cti
- required:
- compatible
+properties:
- $nodename:
- pattern: "^cti(@[0-9a-f,]+)*$"
- compatible:
- items:
- const: arm,coresight-cti
- const: arm,primecell
- reg:
- items:
- description: device programming registers
- arm,cti-v8-arch:
If possible, please could we make this :
"arm,cti-arm-v8-architected"
to be more meaning ful ?
Per my comments to Rob, the v8-cti case will be a compatible option, so this will disappear as an attribute.
- type: boolean
- description:
This CTI follows the v8 architecturally mandated layout for a CTI.
Bindings declaring this must declare a cpu, and optionally 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.
- cpu:
- allOf:
- $ref: /schemas/types.yaml#/definitions/phandle
- description: Handle to cpu this device is associated with.
- arm,cti-ctm-id:
- allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- description:
Defines the CTM this CTI is connected to, in large systems with multiple
separate CTI/CTM nets. Typically multi-socket systems where the CTM is
propagated between sockets.
- arm,cs-dev-assoc:
- allOf:
- $ref: /schemas/types.yaml#/definitions/phandle
- description:
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.
+patternProperties:
- '^trig_conns@[0-9]+$':
I understand these bindings have been around for quite long and is too late to make any changes. So, feel free to ignore this suggestion below and I am perfectly fine with it.
--- Begin silly comments Or Skip to DONE ----
Could we make the property names a bit more obvious ? Since they are supposed to be written by other people (unlike our variable names), it always makes sense to have expanded, meaningful names:
s/trig_conns@/triggers@ ?
s/arm,trig-{in,out}-sigs/arm,cti-{in,out}-triggers s/arm,trig-{in,out}-types/arm,cti-{in,out}-trigger-types
"arm,trig-xxx" property name doesn't really imply that it is for cti. So, the above changes makes it explicit and more reader friendly.
- type: object
- description:
A trigger connections child node which describes the trigger signals
between this CTI and another hardware device. This device may be a CPU,
CoreSight device, any other hardware device or simple external IO lines.
The connection may have both input and output triggers, or only one or the
other.
- properties:
arm,trig-in-sigs:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of CTI trigger in signal numbers in use by a trig-conns node.
arm,trig-in-types:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of constants representing the 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:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of CTI trigger out signal numbers in use by a trig-conns node.
arm,trig-out-types:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of constants representing the 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:
arm,cti-trigger-filters ?
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 32
description:
List of CTI trigger out signals that will be blocked from becoming
active, unless filtering is disabled on the driver.
arm,trig-conn-name:
arm,cti-trigger-name ?
--- DONE or End of silly comments ---
I appreciate the comments on naming, but my feeling is to differentiate between the trigger signals and the trigger connections group. hence the sub-node has group trig_cons. I was hoping that users would get that these are CTI related by the fact that the root node is cti@...
- # Implementation defined CTI - CPU + ETM connections explicitly defined..
- # Shows use of type constants from dt-bindings/arm/coresight-cti-dt.h
- |
- #include <dt-bindings/arm/coresight-cti-dt.h>
- cti@858000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x858000 0x1000>;
clocks = <&soc_smc50mhz>;
clock-names = "apb_pclk";
arm,cti-ctm-id = <1>;
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>;
};
- };
- # Implementation defined CTI - none CoreSight component connections.
nit: s/none/non ?
OK.
Rest looks fine to me.
Suzuki
Thanks
Mike
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 | 205 ++++++++++++++++++ 1 file changed, 205 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c index 665be86c585d..790dd30b85f5 100644 --- a/drivers/hwtracing/coresight/coresight-cti-platform.c +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -3,10 +3,208 @@ * Copyright (c) 2019, The Linaro Limited. 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; + + if (node == NULL) + return -1; + + 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 const char *of_cti_get_node_name(const struct device_node *node) +{ + if (node) + return node->full_name; + return "unknown"; +} +#else +static int of_cti_get_cpu_at_node(const struct device_node *node) +{ + return -1; +} + +static const char *of_cti_get_node_name(const struct device_node *node) +{ + return "unknown"; +} +#endif + +static int cti_plat_get_cpu_at_node(struct fwnode_handle *fwnode) +{ + if (is_of_node(fwnode)) + return of_cti_get_cpu_at_node(to_of_node(fwnode)); + return -1; +} + +static const char *cti_plat_get_node_name(struct fwnode_handle *fwnode) +{ + if (is_of_node(fwnode)) + return of_cti_get_node_name(to_of_node(fwnode)); + return "unknown"; +} + +static int cti_plat_create_v8_etm_connection(struct device *dev, + struct cti_drvdata *drvdata) +{ + int ret = -ENOMEM, i; + struct fwnode_handle *root_fwnode, *cs_fwnode; + const char *assoc_name = NULL; + struct coresight_device *csdev; + struct cti_trig_con *tc = NULL; + + root_fwnode = dev_fwnode(dev); + if (IS_ERR_OR_NULL(root_fwnode)) + return -EINVAL; + + /* Can optionally have an etm node - return if not */ + cs_fwnode = fwnode_find_reference(root_fwnode, CTI_DT_CSDEV_ASSOC, 0); + if (IS_ERR_OR_NULL(cs_fwnode)) + return 0; + + /* allocate memory */ + tc = cti_allocate_trig_con(dev, NR_V8ETM_INOUT_SIGS, + NR_V8ETM_INOUT_SIGS); + if (!tc) + goto 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> */ + + /* + * The EXTOUT type signals from the ETM are connected to a set of input + * triggers on the CTI, the EXTIN being connected to output triggers. + */ + 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; + } + + /* + * We look to see if the ETM coresight device associated with this + * handle has been registered with the system - i.e. probed before + * this CTI. If so csdev will be non NULL and we can use the device + * name and pass the csdev to the connection entry function where + * the association will be recorded. + * If not, then simply record the name in the connection data, the + * probing of the ETM will call into the CTI driver API to update the + * association then. + */ + csdev = cti_get_assoc_csdev_by_fwnode(cs_fwnode); + if (csdev) + assoc_name = dev_name(&csdev->dev); + else + assoc_name = cti_plat_get_node_name(cs_fwnode); + ret = cti_add_connection_entry(dev, drvdata, tc, csdev, assoc_name); + +create_v8_etm_out: + fwnode_handle_put(cs_fwnode); + return ret; +} + +/* + * Create an architecturally defined v8 connection + * must have a cpu, can have an ETM. + */ +static int cti_plat_create_v8_connections(struct device *dev, + struct cti_drvdata *drvdata) +{ + 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 = cti_plat_get_cpu_at_node(dev_fwnode(dev)); + 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 = cti_plat_create_v8_etm_connection(dev, drvdata); + 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 cti_plat_get_hw_data(struct device *dev, struct cti_drvdata *drvdata) @@ -14,6 +212,13 @@ int cti_plat_get_hw_data(struct device *dev, int rc = 0; struct cti_device *cti_dev = &drvdata->ctidev;
+ /* check for a v8 architectural CTI device */ + if (device_property_read_bool(dev, CTI_DT_V8ARCH)) { + rc = cti_plat_create_v8_connections(dev, drvdata); + 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 Tue, Nov 19, 2019 at 11:19:04PM +0000, 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 | 205 ++++++++++++++++++ 1 file changed, 205 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c index 665be86c585d..790dd30b85f5 100644 --- a/drivers/hwtracing/coresight/coresight-cti-platform.c +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -3,10 +3,208 @@
- Copyright (c) 2019, The Linaro Limited. 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;
- if (node == NULL)
return -1;
- 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 const char *of_cti_get_node_name(const struct device_node *node) +{
- if (node)
return node->full_name;
- return "unknown";
+} +#else +static int of_cti_get_cpu_at_node(const struct device_node *node) +{
- return -1;
+}
+static const char *of_cti_get_node_name(const struct device_node *node) +{
- return "unknown";
+} +#endif
+static int cti_plat_get_cpu_at_node(struct fwnode_handle *fwnode) +{
- if (is_of_node(fwnode))
return of_cti_get_cpu_at_node(to_of_node(fwnode));
- return -1;
+}
+static const char *cti_plat_get_node_name(struct fwnode_handle *fwnode) +{
- if (is_of_node(fwnode))
return of_cti_get_node_name(to_of_node(fwnode));
- return "unknown";
+}
+static int cti_plat_create_v8_etm_connection(struct device *dev,
struct cti_drvdata *drvdata)
+{
- int ret = -ENOMEM, i;
- struct fwnode_handle *root_fwnode, *cs_fwnode;
- const char *assoc_name = NULL;
- struct coresight_device *csdev;
- struct cti_trig_con *tc = NULL;
- root_fwnode = dev_fwnode(dev);
- if (IS_ERR_OR_NULL(root_fwnode))
return -EINVAL;
- /* Can optionally have an etm node - return if not */
- cs_fwnode = fwnode_find_reference(root_fwnode, CTI_DT_CSDEV_ASSOC, 0);
- if (IS_ERR_OR_NULL(cs_fwnode))
return 0;
- /* allocate memory */
- tc = cti_allocate_trig_con(dev, NR_V8ETM_INOUT_SIGS,
NR_V8ETM_INOUT_SIGS);
- if (!tc)
goto 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> */
- /*
* The EXTOUT type signals from the ETM are connected to a set of input
* triggers on the CTI, the EXTIN being connected to output triggers.
*/
- 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;
- }
- /*
* We look to see if the ETM coresight device associated with this
* handle has been registered with the system - i.e. probed before
* this CTI. If so csdev will be non NULL and we can use the device
* name and pass the csdev to the connection entry function where
* the association will be recorded.
* If not, then simply record the name in the connection data, the
* probing of the ETM will call into the CTI driver API to update the
* association then.
*/
- csdev = cti_get_assoc_csdev_by_fwnode(cs_fwnode);
- if (csdev)
assoc_name = dev_name(&csdev->dev);
- else
assoc_name = cti_plat_get_node_name(cs_fwnode);
- ret = cti_add_connection_entry(dev, drvdata, tc, csdev, assoc_name);
+create_v8_etm_out:
- fwnode_handle_put(cs_fwnode);
- return ret;
+}
+/*
- Create an architecturally defined v8 connection
- must have a cpu, can have an ETM.
- */
+static int cti_plat_create_v8_connections(struct device *dev,
struct cti_drvdata *drvdata)
+{
- 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 = cti_plat_get_cpu_at_node(dev_fwnode(dev));
- 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 = cti_plat_create_v8_etm_connection(dev, drvdata);
- 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 cti_plat_get_hw_data(struct device *dev, struct cti_drvdata *drvdata) @@ -14,6 +212,13 @@ int cti_plat_get_hw_data(struct device *dev, int rc = 0; struct cti_device *cti_dev = &drvdata->ctidev;
- /* check for a v8 architectural CTI device */
- if (device_property_read_bool(dev, CTI_DT_V8ARCH)) {
rc = cti_plat_create_v8_connections(dev, drvdata);
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);
Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org
-- 2.17.1
On 19/11/2019 23:19, 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 | 205 ++++++++++++++++++ 1 file changed, 205 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c index 665be86c585d..790dd30b85f5 100644 --- a/drivers/hwtracing/coresight/coresight-cti-platform.c +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -3,10 +3,208 @@
- Copyright (c) 2019, The Linaro Limited. 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)
To be frank this has nothing to do with the CTI and is in a way a good candidate for a CoreSight generic function. We do similar stuff in coresight_fixup_device_conns(). So this could be :
struct coresight_device * coresight_find_device_by_fwnode(const struct fwnode_handle *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;
+}
And used in coresight_fixup_conns().
+#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;
- if (node == NULL)
return -1;
- 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 const char *of_cti_get_node_name(const struct device_node *node) +{
- if (node)
return node->full_name;
- return "unknown";
+} +#else +static int of_cti_get_cpu_at_node(const struct device_node *node) +{
- return -1;
+}
+static const char *of_cti_get_node_name(const struct device_node *node) +{
- return "unknown";
+} +#endif
+static int cti_plat_get_cpu_at_node(struct fwnode_handle *fwnode) +{
You may simply reuse coresight_get_cpu() below, instead of adding this duplicate set of functions. See below.
+static int cti_plat_create_v8_etm_connection(struct device *dev,
struct cti_drvdata *drvdata)
+{
- int ret = -ENOMEM, i;
- struct fwnode_handle *root_fwnode, *cs_fwnode;
- const char *assoc_name = NULL;
- struct coresight_device *csdev;
- struct cti_trig_con *tc = NULL;
- root_fwnode = dev_fwnode(dev);
- if (IS_ERR_OR_NULL(root_fwnode))
return -EINVAL;
- /* Can optionally have an etm node - return if not */
- cs_fwnode = fwnode_find_reference(root_fwnode, CTI_DT_CSDEV_ASSOC, 0);
- if (IS_ERR_OR_NULL(cs_fwnode))
return 0;
- /* allocate memory */
- tc = cti_allocate_trig_con(dev, NR_V8ETM_INOUT_SIGS,
NR_V8ETM_INOUT_SIGS);
- if (!tc)
goto 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> */
- /*
* The EXTOUT type signals from the ETM are connected to a set of input
* triggers on the CTI, the EXTIN being connected to output triggers.
*/
- 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;
- }
- /*
* We look to see if the ETM coresight device associated with this
* handle has been registered with the system - i.e. probed before
* this CTI. If so csdev will be non NULL and we can use the device
* name and pass the csdev to the connection entry function where
* the association will be recorded.
* If not, then simply record the name in the connection data, the
* probing of the ETM will call into the CTI driver API to update the
* association then.
*/
- csdev = cti_get_assoc_csdev_by_fwnode(cs_fwnode);
- if (csdev)
assoc_name = dev_name(&csdev->dev);
Does it make sense to defer the probing until the ETM device turn up ? Its fine either way.
- else
assoc_name = cti_plat_get_node_name(cs_fwnode);
- ret = cti_add_connection_entry(dev, drvdata, tc, csdev, assoc_name);
+create_v8_etm_out:
- fwnode_handle_put(cs_fwnode);
- return ret;
+}
+/*
- Create an architecturally defined v8 connection
- must have a cpu, can have an ETM.
- */
+static int cti_plat_create_v8_connections(struct device *dev,
struct cti_drvdata *drvdata)
+{
- 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 = cti_plat_get_cpu_at_node(dev_fwnode(dev));
Could we reuse coresight_get_cpu(dev) instead ? I understand that the ACPI bindings have not been defined and it may be slightly different from what we have now for the ETMs (i.e, ETM node as child of the CPU node). But I don't see why we can't force it for the CTIs either. In the worst case, you could still reuse the of_coresgith_get_cpu(dev) instead of writing your own for the OF case.
- if (cpuid < 0) {
dev_warn(dev, "CTI v8 DT binding no cpu\n");
This may be better off without mentioning the DT. e.g,
"CTI Arm v8 architected connection: missing 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 = cti_plat_create_v8_etm_connection(dev, drvdata);
- 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 cti_plat_get_hw_data(struct device *dev, struct cti_drvdata *drvdata)
@@ -14,6 +212,13 @@ int cti_plat_get_hw_data(struct device *dev, int rc = 0; struct cti_device *cti_dev = &drvdata->ctidev;
- /* check for a v8 architectural CTI device */
minor nit: Check for Arm v8 architected CTI connection ?
- if (device_property_read_bool(dev, CTI_DT_V8ARCH)) {
rc = cti_plat_create_v8_connections(dev, drvdata);
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);
Suzuki
Hi Suzuki,
On Fri, 29 Nov 2019 at 11:33, Suzuki Kuruppassery Poulose suzuki.poulose@arm.com wrote:
On 19/11/2019 23:19, 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 | 205 ++++++++++++++++++ 1 file changed, 205 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c index 665be86c585d..790dd30b85f5 100644 --- a/drivers/hwtracing/coresight/coresight-cti-platform.c +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -3,10 +3,208 @@
- Copyright (c) 2019, The Linaro Limited. 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)
To be frank this has nothing to do with the CTI and is in a way a good candidate for a CoreSight generic function. We do similar stuff in coresight_fixup_device_conns(). So this could be :
struct coresight_device * coresight_find_device_by_fwnode(const struct fwnode_handle *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;
+}
And used in coresight_fixup_conns().
OK - I'll look at that.
+#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;
if (node == NULL)
return -1;
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 const char *of_cti_get_node_name(const struct device_node *node) +{
if (node)
return node->full_name;
return "unknown";
+} +#else +static int of_cti_get_cpu_at_node(const struct device_node *node) +{
return -1;
+}
+static const char *of_cti_get_node_name(const struct device_node *node) +{
return "unknown";
+} +#endif
+static int cti_plat_get_cpu_at_node(struct fwnode_handle *fwnode) +{
You may simply reuse coresight_get_cpu() below, instead of adding this duplicate set of functions. See below.
No we can't. coresight_get_cpu gets the 'cpu' entry relative to the device node, this gets the 'cpu' relative to the supplied node. This is very important for the case where a none v8 architected PE is attached to a CTI. This will use the devicetree form:-
cti@<addr> { [ some stuff ] trig_conns@1 { cpu = <&CPU0> [trigger signal connection info for this cpu] } }
trig_conns is a child node and we must look for 'cpu' relative to it.
+static int cti_plat_create_v8_etm_connection(struct device *dev,
struct cti_drvdata *drvdata)
+{
int ret = -ENOMEM, i;
struct fwnode_handle *root_fwnode, *cs_fwnode;
const char *assoc_name = NULL;
struct coresight_device *csdev;
struct cti_trig_con *tc = NULL;
root_fwnode = dev_fwnode(dev);
if (IS_ERR_OR_NULL(root_fwnode))
return -EINVAL;
/* Can optionally have an etm node - return if not */
cs_fwnode = fwnode_find_reference(root_fwnode, CTI_DT_CSDEV_ASSOC, 0);
if (IS_ERR_OR_NULL(cs_fwnode))
return 0;
/* allocate memory */
tc = cti_allocate_trig_con(dev, NR_V8ETM_INOUT_SIGS,
NR_V8ETM_INOUT_SIGS);
if (!tc)
goto 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> */
/*
* The EXTOUT type signals from the ETM are connected to a set of input
* triggers on the CTI, the EXTIN being connected to output triggers.
*/
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;
}
/*
* We look to see if the ETM coresight device associated with this
* handle has been registered with the system - i.e. probed before
* this CTI. If so csdev will be non NULL and we can use the device
* name and pass the csdev to the connection entry function where
* the association will be recorded.
* If not, then simply record the name in the connection data, the
* probing of the ETM will call into the CTI driver API to update the
* association then.
*/
csdev = cti_get_assoc_csdev_by_fwnode(cs_fwnode);
if (csdev)
assoc_name = dev_name(&csdev->dev);
Does it make sense to defer the probing until the ETM device turn up ? Its fine either way.
Not really as the ETM is optional but the PE still has a CTI.
else
assoc_name = cti_plat_get_node_name(cs_fwnode);
ret = cti_add_connection_entry(dev, drvdata, tc, csdev, assoc_name);
+create_v8_etm_out:
fwnode_handle_put(cs_fwnode);
return ret;
+}
+/*
- Create an architecturally defined v8 connection
- must have a cpu, can have an ETM.
- */
+static int cti_plat_create_v8_connections(struct device *dev,
struct cti_drvdata *drvdata)
+{
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 = cti_plat_get_cpu_at_node(dev_fwnode(dev));
Could we reuse coresight_get_cpu(dev) instead ? I understand that the ACPI bindings have not been defined and it may be slightly different from what we have now for the ETMs (i.e, ETM node as child of the CPU node). But I don't see why we can't force it for the CTIs either. In the worst case, you could still reuse the of_coresgith_get_cpu(dev) instead of writing your own for the OF case.
See comments above - in theory here we could use coresight_get_cpu(), but for consistency it is better to use that same function throughout in case someone decided to "fix" it later. I probably need to beef up the comments around cti_plat_get_cpu_at_node / of_cti_get_cpu_at_node.
if (cpuid < 0) {
dev_warn(dev, "CTI v8 DT binding no cpu\n");
This may be better off without mentioning the DT. e.g,
"CTI Arm v8 architected connection: missing CPU\n"
OK
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 = cti_plat_create_v8_etm_connection(dev, drvdata);
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 cti_plat_get_hw_data(struct device *dev, struct cti_drvdata *drvdata)
@@ -14,6 +212,13 @@ int cti_plat_get_hw_data(struct device *dev, int rc = 0; struct cti_device *cti_dev = &drvdata->ctidev;
/* check for a v8 architectural CTI device */
minor nit: Check for Arm v8 architected CTI connection ?
if (device_property_read_bool(dev, CTI_DT_V8ARCH)) {
rc = cti_plat_create_v8_connections(dev, drvdata);
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);
Suzuki
Thanks
Mike
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
On 03/12/2019 10:59, Mike Leach wrote:
Hi Suzuki,
On Fri, 29 Nov 2019 at 11:33, Suzuki Kuruppassery Poulose suzuki.poulose@arm.com wrote:
On 19/11/2019 23:19, 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
+#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;
if (node == NULL)
return -1;
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 const char *of_cti_get_node_name(const struct device_node *node) +{
if (node)
return node->full_name;
return "unknown";
+} +#else +static int of_cti_get_cpu_at_node(const struct device_node *node) +{
return -1;
+}
+static const char *of_cti_get_node_name(const struct device_node *node) +{
return "unknown";
+} +#endif
+static int cti_plat_get_cpu_at_node(struct fwnode_handle *fwnode) +{
You may simply reuse coresight_get_cpu() below, instead of adding this duplicate set of functions. See below.
No we can't. coresight_get_cpu gets the 'cpu' entry relative to the device node, this gets the 'cpu' relative to the supplied node. This is very important for the case where a none v8 architected PE is attached to a CTI. This will use the devicetree form:-
cti@<addr> { [ some stuff ] trig_conns@1 { cpu = <&CPU0> [trigger signal connection info for this cpu] } }
trig_conns is a child node and we must look for 'cpu' relative to it.
Ok. May be we could refactor the function to find the 'CPU' node relative to the given "fwnode" and let the coresight_get_cpu() use it ?
int coresight_get_cpu(struct device *dev) { return coresight_get_fwnode_cpu(dev_fwnode(dev)); }
That way it is clear what we are dealing with. i.e, fwnode of any level (device or an intermediate node).
csdev = cti_get_assoc_csdev_by_fwnode(cs_fwnode);
if (csdev)
assoc_name = dev_name(&csdev->dev);
Does it make sense to defer the probing until the ETM device turn up ? Its fine either way.
Not really as the ETM is optional but the PE still has a CTI.
Ah, you're right. Please ignore my comment.
Kind regards Suzuki
Hi Suzuki,
On Tue, 3 Dec 2019 at 11:28, Suzuki Kuruppassery Poulose suzuki.poulose@arm.com wrote:
On 03/12/2019 10:59, Mike Leach wrote:
Hi Suzuki,
On Fri, 29 Nov 2019 at 11:33, Suzuki Kuruppassery Poulose suzuki.poulose@arm.com wrote:
On 19/11/2019 23:19, 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
+#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;
if (node == NULL)
return -1;
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 const char *of_cti_get_node_name(const struct device_node *node) +{
if (node)
return node->full_name;
return "unknown";
+} +#else +static int of_cti_get_cpu_at_node(const struct device_node *node) +{
return -1;
+}
+static const char *of_cti_get_node_name(const struct device_node *node) +{
return "unknown";
+} +#endif
+static int cti_plat_get_cpu_at_node(struct fwnode_handle *fwnode) +{
You may simply reuse coresight_get_cpu() below, instead of adding this duplicate set of functions. See below.
No we can't. coresight_get_cpu gets the 'cpu' entry relative to the device node, this gets the 'cpu' relative to the supplied node. This is very important for the case where a none v8 architected PE is attached to a CTI. This will use the devicetree form:-
cti@<addr> { [ some stuff ] trig_conns@1 { cpu = <&CPU0> [trigger signal connection info for this cpu] } }
trig_conns is a child node and we must look for 'cpu' relative to it.
Ok. May be we could refactor the function to find the 'CPU' node relative to the given "fwnode" and let the coresight_get_cpu() use it ?
int coresight_get_cpu(struct device *dev) { return coresight_get_fwnode_cpu(dev_fwnode(dev)); }
That way it is clear what we are dealing with. i.e, fwnode of any level (device or an intermediate node).
At present the generic coresight_get_cpu() deals with both DT and ACPI bindings. To refactor this would require re-factoring both binding types - and at present we have no definition for ACPI bindings for CTI and hence no way of knowing how the embedded cpu node is going to be represented.
I think we have to take just the DT binding as is for now as a CTI specific element and consider if it is worth re-factoring once the ACPI bindings are defined
Regards
Mike
csdev = cti_get_assoc_csdev_by_fwnode(cs_fwnode);
if (csdev)
assoc_name = dev_name(&csdev->dev);
Does it make sense to defer the probing until the ETM device turn up ? Its fine either way.
Not really as the ETM is optional but the PE still has a CTI.
Ah, you're right. Please ignore my comment.
Kind regards Suzuki
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 | 250 +++++++++++++++++- .../hwtracing/coresight/coresight-cti-sysfs.c | 11 + 2 files changed, 257 insertions(+), 4 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c index 790dd30b85f5..9c1ff432b487 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_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" +#define CTI_DT_CTM_ID "arm,cti-ctm-id"
/* * Find a registered coresight device from a device fwnode. @@ -68,6 +78,12 @@ static const char *of_cti_get_node_name(const struct device_node *node) return node->full_name; return "unknown"; } + +static bool of_cti_node_name_eq(const struct device_node *node, + const char *name) +{ + return of_node_name_eq(node, name); +} #else static int of_cti_get_cpu_at_node(const struct device_node *node) { @@ -78,6 +94,12 @@ static const char *of_cti_get_node_name(const struct device_node *node) { return "unknown"; } + +static bool of_cti_node_name_eq(const struct device_node *node, + const char *name) +{ + return false; +} #endif
static int cti_plat_get_cpu_at_node(struct fwnode_handle *fwnode) @@ -94,6 +116,14 @@ static const char *cti_plat_get_node_name(struct fwnode_handle *fwnode) return "unknown"; }
+static bool cti_plat_node_name_eq(struct fwnode_handle *fwnode, + const char *name) +{ + if (is_of_node(fwnode)) + return of_cti_node_name_eq(to_of_node(fwnode), name); + return false; +} + static int cti_plat_create_v8_etm_connection(struct device *dev, struct cti_drvdata *drvdata) { @@ -205,6 +235,214 @@ static int cti_plat_create_v8_connections(struct device *dev, return ret; }
+static int cti_plat_count_sig_elements(const struct fwnode_handle *fwnode, + const char *name) +{ + int nr_elem = fwnode_property_count_u32(fwnode, name); + + return (nr_elem < 0 ? 0 : nr_elem); +} + +static int cti_plat_read_trig_group(struct cti_trig_grp *tgrp, + const struct fwnode_handle *fwnode, + const char *grp_name) +{ + int idx, err = 0; + u32 *values; + + if (!tgrp->nr_sigs) + return 0; + + values = kcalloc(tgrp->nr_sigs, sizeof(u32), GFP_KERNEL); + if (!values) + return -ENOMEM; + + err = fwnode_property_read_u32_array(fwnode, grp_name, + values, tgrp->nr_sigs); + + if (!err) { + /* set the signal usage mask */ + for (idx = 0; idx < tgrp->nr_sigs; idx++) + tgrp->used_mask |= BIT(values[idx]); + } + + kfree(values); + return err; +} + +static int cti_plat_read_trig_types(struct cti_trig_grp *tgrp, + const struct fwnode_handle *fwnode, + const char *type_name) +{ + int items, used = 0, err = 0, nr_sigs; + u32 *values = NULL, 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 = cti_plat_count_sig_elements(fwnode, type_name); + if (items > nr_sigs) + return -EINVAL; + + /* need an array to store the values iff there are any */ + if (items) { + values = kcalloc(items, sizeof(u32), GFP_KERNEL); + if (!values) + return -ENOMEM; + + err = fwnode_property_read_u32_array(fwnode, type_name, + values, items); + if (err) + goto read_trig_types_out; + } + + /* + * Match type id to signal index, 1st type to 1st index etc. + * If fewer types than signals default remainder to GEN_IO. + */ + for (i = 0; i < nr_sigs; i++) { + if (used < items) { + tgrp->sig_types[i] = + values[i] < CTI_TRIG_MAX ? values[i] : GEN_IO; + used++; + } else { + tgrp->sig_types[i] = GEN_IO; + } + } + +read_trig_types_out: + kfree(values); + return err; +} + +static int cti_plat_process_filter_sigs(struct cti_drvdata *drvdata, + const struct fwnode_handle *fwnode) +{ + struct cti_trig_grp *tg = NULL; + int err = 0, nr_filter_sigs; + + nr_filter_sigs = cti_plat_count_sig_elements(fwnode, + 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 = cti_plat_read_trig_group(tg, fwnode, CTI_DT_FILTER_OUT_SIGS); + if (!err) + drvdata->config.trig_out_filter |= tg->used_mask; + + kfree(tg); + return err; +} + +static int cti_plat_create_connection(struct device *dev, + struct cti_drvdata *drvdata, + struct fwnode_handle *fwnode) +{ + struct cti_trig_con *tc = NULL; + int cpuid = -1, err = 0; + struct fwnode_handle *cs_fwnode = NULL; + struct coresight_device *csdev = NULL; + const char *assoc_name = "unknown"; + char cpu_name_str[16]; + int nr_sigs_in, nr_sigs_out; + + /* look to see how many in and out signals we have */ + nr_sigs_in = cti_plat_count_sig_elements(fwnode, CTI_DT_TRIGIN_SIGS); + nr_sigs_out = cti_plat_count_sig_elements(fwnode, 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 = cti_plat_read_trig_group(tc->con_in, fwnode, + CTI_DT_TRIGIN_SIGS); + if (err) + goto create_con_err; + + err = cti_plat_read_trig_types(tc->con_in, fwnode, + CTI_DT_TRIGIN_TYPES); + if (err) + goto create_con_err; + + err = cti_plat_read_trig_group(tc->con_out, fwnode, + CTI_DT_TRIGOUT_SIGS); + if (err) + goto create_con_err; + + err = cti_plat_read_trig_types(tc->con_out, fwnode, + CTI_DT_TRIGOUT_TYPES); + if (err) + goto create_con_err; + + err = cti_plat_process_filter_sigs(drvdata, fwnode); + if (err) + goto create_con_err; + + /* read the connection name if set - may be overridden by later */ + fwnode_property_read_string(fwnode, CTI_DT_CONN_NAME, &assoc_name); + + /* associated cpu ? */ + cpuid = cti_plat_get_cpu_at_node(fwnode); + 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_fwnode = fwnode_find_reference(fwnode, + CTI_DT_CSDEV_ASSOC, 0); + if (!IS_ERR_OR_NULL(cs_fwnode)) { + csdev = cti_get_assoc_csdev_by_fwnode(cs_fwnode); + if (csdev) /* use device name if csdev found */ + assoc_name = dev_name(&csdev->dev); + else /* otherwise node name for later association */ + assoc_name = cti_plat_get_node_name(cs_fwnode); + fwnode_handle_put(cs_fwnode); + } + } + /* set up a connection */ + err = cti_add_connection_entry(dev, drvdata, tc, csdev, assoc_name); + +create_con_err: + return err; +} + +static int cti_plat_create_impdef_connections(struct device *dev, + struct cti_drvdata *drvdata) +{ + int rc = 0; + struct fwnode_handle *fwnode = dev_fwnode(dev); + struct fwnode_handle *child = NULL; + + if (IS_ERR_OR_NULL(fwnode)) + return -EINVAL; + + fwnode_for_each_child_node(fwnode, child) { + if (cti_plat_node_name_eq(child, CTI_DT_CONNS)) + rc = cti_plat_create_connection(dev, drvdata, child); + if (rc != 0) + break; + } + fwnode_handle_put(child); + + return rc; +} + /* get the hardware configuration & connection data. */ int cti_plat_get_hw_data(struct device *dev, struct cti_drvdata *drvdata) @@ -212,12 +450,16 @@ int cti_plat_get_hw_data(struct device *dev, int rc = 0; struct cti_device *cti_dev = &drvdata->ctidev;
+ /* get any CTM ID - defaults to 0 */ + device_property_read_u32(dev, CTI_DT_CTM_ID, &cti_dev->ctm_id); + /* check for a v8 architectural CTI device */ - if (device_property_read_bool(dev, CTI_DT_V8ARCH)) { + if (device_property_read_bool(dev, CTI_DT_V8ARCH)) rc = cti_plat_create_v8_connections(dev, drvdata); - if (rc) - return rc; - } + else + rc = cti_plat_create_impdef_connections(dev, drvdata); + if (rc) + return rc;
/* if no connections, just add a single default based on max IN-OUT */ if (cti_dev->nr_trig_con == 0) diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 98de8a4768fc..f800402f73da 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -56,9 +56,20 @@ 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, };
On Tue, Nov 19, 2019 at 11:19:05PM +0000, 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 | 250 +++++++++++++++++- .../hwtracing/coresight/coresight-cti-sysfs.c | 11 + 2 files changed, 257 insertions(+), 4 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c index 790dd30b85f5..9c1ff432b487 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_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" +#define CTI_DT_CTM_ID "arm,cti-ctm-id" /*
- Find a registered coresight device from a device fwnode.
@@ -68,6 +78,12 @@ static const char *of_cti_get_node_name(const struct device_node *node) return node->full_name; return "unknown"; }
+static bool of_cti_node_name_eq(const struct device_node *node,
const char *name)
+{
- return of_node_name_eq(node, name);
+} #else static int of_cti_get_cpu_at_node(const struct device_node *node) { @@ -78,6 +94,12 @@ static const char *of_cti_get_node_name(const struct device_node *node) { return "unknown"; }
+static bool of_cti_node_name_eq(const struct device_node *node,
const char *name)
+{
- return false;
+} #endif static int cti_plat_get_cpu_at_node(struct fwnode_handle *fwnode) @@ -94,6 +116,14 @@ static const char *cti_plat_get_node_name(struct fwnode_handle *fwnode) return "unknown"; } +static bool cti_plat_node_name_eq(struct fwnode_handle *fwnode,
const char *name)
+{
- if (is_of_node(fwnode))
return of_cti_node_name_eq(to_of_node(fwnode), name);
- return false;
+}
static int cti_plat_create_v8_etm_connection(struct device *dev, struct cti_drvdata *drvdata) { @@ -205,6 +235,214 @@ static int cti_plat_create_v8_connections(struct device *dev, return ret; } +static int cti_plat_count_sig_elements(const struct fwnode_handle *fwnode,
const char *name)
+{
- int nr_elem = fwnode_property_count_u32(fwnode, name);
- return (nr_elem < 0 ? 0 : nr_elem);
+}
+static int cti_plat_read_trig_group(struct cti_trig_grp *tgrp,
const struct fwnode_handle *fwnode,
const char *grp_name)
+{
- int idx, err = 0;
- u32 *values;
- if (!tgrp->nr_sigs)
return 0;
- values = kcalloc(tgrp->nr_sigs, sizeof(u32), GFP_KERNEL);
- if (!values)
return -ENOMEM;
- err = fwnode_property_read_u32_array(fwnode, grp_name,
values, tgrp->nr_sigs);
- if (!err) {
/* set the signal usage mask */
for (idx = 0; idx < tgrp->nr_sigs; idx++)
tgrp->used_mask |= BIT(values[idx]);
- }
- kfree(values);
- return err;
+}
+static int cti_plat_read_trig_types(struct cti_trig_grp *tgrp,
const struct fwnode_handle *fwnode,
const char *type_name)
+{
- int items, used = 0, err = 0, nr_sigs;
- u32 *values = NULL, 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 = cti_plat_count_sig_elements(fwnode, type_name);
- if (items > nr_sigs)
return -EINVAL;
- /* need an array to store the values iff there are any */
- if (items) {
values = kcalloc(items, sizeof(u32), GFP_KERNEL);
if (!values)
return -ENOMEM;
err = fwnode_property_read_u32_array(fwnode, type_name,
values, items);
if (err)
goto read_trig_types_out;
- }
- /*
* Match type id to signal index, 1st type to 1st index etc.
* If fewer types than signals default remainder to GEN_IO.
*/
- for (i = 0; i < nr_sigs; i++) {
if (used < items) {
tgrp->sig_types[i] =
values[i] < CTI_TRIG_MAX ? values[i] : GEN_IO;
used++;
} else {
tgrp->sig_types[i] = GEN_IO;
}
- }
+read_trig_types_out:
- kfree(values);
- return err;
+}
+static int cti_plat_process_filter_sigs(struct cti_drvdata *drvdata,
const struct fwnode_handle *fwnode)
+{
- struct cti_trig_grp *tg = NULL;
- int err = 0, nr_filter_sigs;
- nr_filter_sigs = cti_plat_count_sig_elements(fwnode,
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 = cti_plat_read_trig_group(tg, fwnode, CTI_DT_FILTER_OUT_SIGS);
- if (!err)
drvdata->config.trig_out_filter |= tg->used_mask;
- kfree(tg);
- return err;
+}
+static int cti_plat_create_connection(struct device *dev,
struct cti_drvdata *drvdata,
struct fwnode_handle *fwnode)
+{
- struct cti_trig_con *tc = NULL;
- int cpuid = -1, err = 0;
- struct fwnode_handle *cs_fwnode = NULL;
- struct coresight_device *csdev = NULL;
- const char *assoc_name = "unknown";
- char cpu_name_str[16];
- int nr_sigs_in, nr_sigs_out;
- /* look to see how many in and out signals we have */
- nr_sigs_in = cti_plat_count_sig_elements(fwnode, CTI_DT_TRIGIN_SIGS);
- nr_sigs_out = cti_plat_count_sig_elements(fwnode, 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 = cti_plat_read_trig_group(tc->con_in, fwnode,
CTI_DT_TRIGIN_SIGS);
- if (err)
goto create_con_err;
- err = cti_plat_read_trig_types(tc->con_in, fwnode,
CTI_DT_TRIGIN_TYPES);
- if (err)
goto create_con_err;
- err = cti_plat_read_trig_group(tc->con_out, fwnode,
CTI_DT_TRIGOUT_SIGS);
- if (err)
goto create_con_err;
- err = cti_plat_read_trig_types(tc->con_out, fwnode,
CTI_DT_TRIGOUT_TYPES);
- if (err)
goto create_con_err;
- err = cti_plat_process_filter_sigs(drvdata, fwnode);
- if (err)
goto create_con_err;
- /* read the connection name if set - may be overridden by later */
- fwnode_property_read_string(fwnode, CTI_DT_CONN_NAME, &assoc_name);
- /* associated cpu ? */
- cpuid = cti_plat_get_cpu_at_node(fwnode);
- 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_fwnode = fwnode_find_reference(fwnode,
CTI_DT_CSDEV_ASSOC, 0);
if (!IS_ERR_OR_NULL(cs_fwnode)) {
csdev = cti_get_assoc_csdev_by_fwnode(cs_fwnode);
if (csdev) /* use device name if csdev found */
assoc_name = dev_name(&csdev->dev);
else /* otherwise node name for later association */
assoc_name = cti_plat_get_node_name(cs_fwnode);
fwnode_handle_put(cs_fwnode);
}
- }
- /* set up a connection */
- err = cti_add_connection_entry(dev, drvdata, tc, csdev, assoc_name);
+create_con_err:
- return err;
+}
+static int cti_plat_create_impdef_connections(struct device *dev,
struct cti_drvdata *drvdata)
+{
- int rc = 0;
- struct fwnode_handle *fwnode = dev_fwnode(dev);
- struct fwnode_handle *child = NULL;
- if (IS_ERR_OR_NULL(fwnode))
return -EINVAL;
- fwnode_for_each_child_node(fwnode, child) {
if (cti_plat_node_name_eq(child, CTI_DT_CONNS))
rc = cti_plat_create_connection(dev, drvdata, child);
if (rc != 0)
break;
- }
- fwnode_handle_put(child);
As far as I can tell we don't need to call fwnode_handle_put()?
With the above: Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org
- return rc;
+}
/* get the hardware configuration & connection data. */ int cti_plat_get_hw_data(struct device *dev, struct cti_drvdata *drvdata) @@ -212,12 +450,16 @@ int cti_plat_get_hw_data(struct device *dev, int rc = 0; struct cti_device *cti_dev = &drvdata->ctidev;
- /* get any CTM ID - defaults to 0 */
- device_property_read_u32(dev, CTI_DT_CTM_ID, &cti_dev->ctm_id);
- /* check for a v8 architectural CTI device */
- if (device_property_read_bool(dev, CTI_DT_V8ARCH)) {
- if (device_property_read_bool(dev, CTI_DT_V8ARCH)) rc = cti_plat_create_v8_connections(dev, drvdata);
if (rc)
return rc;
- }
- else
rc = cti_plat_create_impdef_connections(dev, drvdata);
- if (rc)
return rc;
/* if no connections, just add a single default based on max IN-OUT */ if (cti_dev->nr_trig_con == 0) diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 98de8a4768fc..f800402f73da 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -56,9 +56,20 @@ 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,
}; -- 2.17.1
On 25/11/2019 21:22, Mathieu Poirier wrote:
On Tue, Nov 19, 2019 at 11:19:05PM +0000, 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 | 250 +++++++++++++++++- .../hwtracing/coresight/coresight-cti-sysfs.c | 11 + 2 files changed, 257 insertions(+), 4 deletions(-)
+static int cti_plat_create_impdef_connections(struct device *dev,
struct cti_drvdata *drvdata)
+{
- int rc = 0;
- struct fwnode_handle *fwnode = dev_fwnode(dev);
- struct fwnode_handle *child = NULL;
- if (IS_ERR_OR_NULL(fwnode))
return -EINVAL;
- fwnode_for_each_child_node(fwnode, child) {
if (cti_plat_node_name_eq(child, CTI_DT_CONNS))
rc = cti_plat_create_connection(dev, drvdata, child);
if (rc != 0)
break;
- }
- fwnode_handle_put(child);
As far as I can tell we don't need to call fwnode_handle_put()?
Actually we do, if we break the scan in between, at least for of_nodes. I had to literally look it down all the way down to confirm this.
So for CONFIG_OF it ends up in of_get_next_available_child(), which drops the ref on "prev" and grabs the "next". So in case we break the loop, we must drop the ref on the child. Otherwise, the last result would be NULL, which would have dropped the ref on the "last" valid entry. And this is harmless with a NULL ptr.
Suzuki
On Fri, 29 Nov 2019 at 07:16, Suzuki Kuruppassery Poulose suzuki.poulose@arm.com wrote:
On 25/11/2019 21:22, Mathieu Poirier wrote:
On Tue, Nov 19, 2019 at 11:19:05PM +0000, 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 | 250 +++++++++++++++++- .../hwtracing/coresight/coresight-cti-sysfs.c | 11 + 2 files changed, 257 insertions(+), 4 deletions(-)
+static int cti_plat_create_impdef_connections(struct device *dev,
struct cti_drvdata *drvdata)
+{
- int rc = 0;
- struct fwnode_handle *fwnode = dev_fwnode(dev);
- struct fwnode_handle *child = NULL;
- if (IS_ERR_OR_NULL(fwnode))
return -EINVAL;
- fwnode_for_each_child_node(fwnode, child) {
if (cti_plat_node_name_eq(child, CTI_DT_CONNS))
rc = cti_plat_create_connection(dev, drvdata, child);
if (rc != 0)
break;
- }
- fwnode_handle_put(child);
As far as I can tell we don't need to call fwnode_handle_put()?
Actually we do, if we break the scan in between, at least for of_nodes. I had to literally look it down all the way down to confirm this.
So for CONFIG_OF it ends up in of_get_next_available_child(), which drops the ref on "prev" and grabs the "next". So in case we break the loop, we must drop the ref on the child.
Well spotted.
Otherwise, the last result would be NULL, which would have dropped the ref on the "last" valid entry. And this is harmless with a NULL ptr.
Suzuki
On 19/11/2019 23:19, 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 | 250 +++++++++++++++++- .../hwtracing/coresight/coresight-cti-sysfs.c | 11 + 2 files changed, 257 insertions(+), 4 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c index 790dd30b85f5..9c1ff432b487 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_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" +#define CTI_DT_CTM_ID "arm,cti-ctm-id" /*
- Find a registered coresight device from a device fwnode.
@@ -68,6 +78,12 @@ static const char *of_cti_get_node_name(const struct device_node *node) return node->full_name; return "unknown"; }
+static bool of_cti_node_name_eq(const struct device_node *node,
const char *name)
+{
- return of_node_name_eq(node, name);
+} #else static int of_cti_get_cpu_at_node(const struct device_node *node) { @@ -78,6 +94,12 @@ static const char *of_cti_get_node_name(const struct device_node *node) { return "unknown"; }
+static bool of_cti_node_name_eq(const struct device_node *node,
const char *name)
+{
- return false;
+} #endif
nit: You don't need this wrapper of_node_name_eq() is already defined to return false for !CONFIG_OF.
static int cti_plat_get_cpu_at_node(struct fwnode_handle *fwnode) @@ -94,6 +116,14 @@ static const char *cti_plat_get_node_name(struct fwnode_handle *fwnode) return "unknown"; } +static bool cti_plat_node_name_eq(struct fwnode_handle *fwnode,
const char *name)
+{
- if (is_of_node(fwnode))
return of_cti_node_name_eq(to_of_node(fwnode), name);
As mentioned above you could simply use of_node_name_eq() here.
- return false;
+}
- static int cti_plat_create_v8_etm_connection(struct device *dev, struct cti_drvdata *drvdata) {
@@ -205,6 +235,214 @@ static int cti_plat_create_v8_connections(struct device *dev, return ret; } +static int cti_plat_count_sig_elements(const struct fwnode_handle *fwnode,
const char *name)
+{
- int nr_elem = fwnode_property_count_u32(fwnode, name);
- return (nr_elem < 0 ? 0 : nr_elem);
+}
+static int cti_plat_read_trig_group(struct cti_trig_grp *tgrp,
const struct fwnode_handle *fwnode,
const char *grp_name)
+{
- int idx, err = 0;
- u32 *values;
- if (!tgrp->nr_sigs)
return 0;
- values = kcalloc(tgrp->nr_sigs, sizeof(u32), GFP_KERNEL);
- if (!values)
return -ENOMEM;
- err = fwnode_property_read_u32_array(fwnode, grp_name,
values, tgrp->nr_sigs);
- if (!err) {
/* set the signal usage mask */
for (idx = 0; idx < tgrp->nr_sigs; idx++)
tgrp->used_mask |= BIT(values[idx]);
- }
- kfree(values);
- return err;
+}
+static int cti_plat_read_trig_types(struct cti_trig_grp *tgrp,
const struct fwnode_handle *fwnode,
const char *type_name)
+{
- int items, used = 0, err = 0, nr_sigs;
- u32 *values = NULL, 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 = cti_plat_count_sig_elements(fwnode, type_name);
- if (items > nr_sigs)
return -EINVAL;
- /* need an array to store the values iff there are any */
- if (items) {
values = kcalloc(items, sizeof(u32), GFP_KERNEL);
if (!values)
return -ENOMEM;
err = fwnode_property_read_u32_array(fwnode, type_name,
values, items);
if (err)
goto read_trig_types_out;
- }
- /*
* Match type id to signal index, 1st type to 1st index etc.
* If fewer types than signals default remainder to GEN_IO.
*/
- for (i = 0; i < nr_sigs; i++) {
if (used < items) {
tgrp->sig_types[i] =
values[i] < CTI_TRIG_MAX ? values[i] : GEN_IO;
used++;
Do we really need "used" here ? Couldn't this be :
if (i < items) {
}
} else {
+ /* Mark the undefined connections as GEN_IO */ ?
tgrp->sig_types[i] = GEN_IO;
}
- }
...
- /* read the connection name if set - may be overridden by later */
- fwnode_property_read_string(fwnode, CTI_DT_CONN_NAME, &assoc_name);
- /* associated cpu ? */
- cpuid = cti_plat_get_cpu_at_node(fwnode);
- 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_fwnode = fwnode_find_reference(fwnode,
CTI_DT_CSDEV_ASSOC, 0);
if (!IS_ERR_OR_NULL(cs_fwnode)) {
--- Cut - here --
csdev = cti_get_assoc_csdev_by_fwnode(cs_fwnode);
if (csdev) /* use device name if csdev found */
assoc_name = dev_name(&csdev->dev);
else /* otherwise node name for later association */
assoc_name = cti_plat_get_node_name(cs_fwnode);
--- end - here --
I believe we do this for arm_v8 architected connections too. May be make this a helper ?
fwnode_handle_put(cs_fwnode);
}
- }
- /* set up a connection */
- err = cti_add_connection_entry(dev, drvdata, tc, csdev, assoc_name);
+create_con_err:
- return err;
+}
+static int cti_plat_create_impdef_connections(struct device *dev,
struct cti_drvdata *drvdata)
+{
- int rc = 0;
- struct fwnode_handle *fwnode = dev_fwnode(dev);
- struct fwnode_handle *child = NULL;
- if (IS_ERR_OR_NULL(fwnode))
return -EINVAL;
- fwnode_for_each_child_node(fwnode, child) {
if (cti_plat_node_name_eq(child, CTI_DT_CONNS))
rc = cti_plat_create_connection(dev, drvdata, child);
if (rc != 0)
break;
minor nit: To make it more obvious :
if (cti_plat_node_name_eq(child, CTI_DT_CONNS)) { rc = cti_plat_create_connection(dev, drvdata, child); if (rc) break; }
Suzuki
Hi Suzuki,
On Fri, 29 Nov 2019 at 14:18, Suzuki Kuruppassery Poulose suzuki.poulose@arm.com wrote:
On 19/11/2019 23:19, 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 | 250 +++++++++++++++++- .../hwtracing/coresight/coresight-cti-sysfs.c | 11 + 2 files changed, 257 insertions(+), 4 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c index 790dd30b85f5..9c1ff432b487 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_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" +#define CTI_DT_CTM_ID "arm,cti-ctm-id"
/*
- Find a registered coresight device from a device fwnode.
@@ -68,6 +78,12 @@ static const char *of_cti_get_node_name(const struct device_node *node) return node->full_name; return "unknown"; }
+static bool of_cti_node_name_eq(const struct device_node *node,
const char *name)
+{
return of_node_name_eq(node, name);
+} #else static int of_cti_get_cpu_at_node(const struct device_node *node) { @@ -78,6 +94,12 @@ static const char *of_cti_get_node_name(const struct device_node *node) { return "unknown"; }
+static bool of_cti_node_name_eq(const struct device_node *node,
const char *name)
+{
return false;
+} #endif
nit: You don't need this wrapper of_node_name_eq() is already defined to return false for !CONFIG_OF.
OK.
static int cti_plat_get_cpu_at_node(struct fwnode_handle *fwnode) @@ -94,6 +116,14 @@ static const char *cti_plat_get_node_name(struct fwnode_handle *fwnode) return "unknown"; }
+static bool cti_plat_node_name_eq(struct fwnode_handle *fwnode,
const char *name)
+{
if (is_of_node(fwnode))
return of_cti_node_name_eq(to_of_node(fwnode), name);
As mentioned above you could simply use of_node_name_eq() here.
return false;
+}
- static int cti_plat_create_v8_etm_connection(struct device *dev, struct cti_drvdata *drvdata) {
@@ -205,6 +235,214 @@ static int cti_plat_create_v8_connections(struct device *dev, return ret; }
+static int cti_plat_count_sig_elements(const struct fwnode_handle *fwnode,
const char *name)
+{
int nr_elem = fwnode_property_count_u32(fwnode, name);
return (nr_elem < 0 ? 0 : nr_elem);
+}
+static int cti_plat_read_trig_group(struct cti_trig_grp *tgrp,
const struct fwnode_handle *fwnode,
const char *grp_name)
+{
int idx, err = 0;
u32 *values;
if (!tgrp->nr_sigs)
return 0;
values = kcalloc(tgrp->nr_sigs, sizeof(u32), GFP_KERNEL);
if (!values)
return -ENOMEM;
err = fwnode_property_read_u32_array(fwnode, grp_name,
values, tgrp->nr_sigs);
if (!err) {
/* set the signal usage mask */
for (idx = 0; idx < tgrp->nr_sigs; idx++)
tgrp->used_mask |= BIT(values[idx]);
}
kfree(values);
return err;
+}
+static int cti_plat_read_trig_types(struct cti_trig_grp *tgrp,
const struct fwnode_handle *fwnode,
const char *type_name)
+{
int items, used = 0, err = 0, nr_sigs;
u32 *values = NULL, 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 = cti_plat_count_sig_elements(fwnode, type_name);
if (items > nr_sigs)
return -EINVAL;
/* need an array to store the values iff there are any */
if (items) {
values = kcalloc(items, sizeof(u32), GFP_KERNEL);
if (!values)
return -ENOMEM;
err = fwnode_property_read_u32_array(fwnode, type_name,
values, items);
if (err)
goto read_trig_types_out;
}
/*
* Match type id to signal index, 1st type to 1st index etc.
* If fewer types than signals default remainder to GEN_IO.
*/
for (i = 0; i < nr_sigs; i++) {
if (used < items) {
tgrp->sig_types[i] =
values[i] < CTI_TRIG_MAX ? values[i] : GEN_IO;
used++;
Do we really need "used" here ? Couldn't this be :
No we don't - I'll fix it.
if (i < items) { }
} else {
/* Mark the undefined connections as GEN_IO */ ?
tgrp->sig_types[i] = GEN_IO;
}
}
...
/* read the connection name if set - may be overridden by later */
fwnode_property_read_string(fwnode, CTI_DT_CONN_NAME, &assoc_name);
/* associated cpu ? */
cpuid = cti_plat_get_cpu_at_node(fwnode);
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_fwnode = fwnode_find_reference(fwnode,
CTI_DT_CSDEV_ASSOC, 0);
if (!IS_ERR_OR_NULL(cs_fwnode)) {
--- Cut - here --
csdev = cti_get_assoc_csdev_by_fwnode(cs_fwnode);
if (csdev) /* use device name if csdev found */
assoc_name = dev_name(&csdev->dev);
else /* otherwise node name for later association */
assoc_name = cti_plat_get_node_name(cs_fwnode);
--- end - here --
I believe we do this for arm_v8 architected connections too. May be make this a helper ?
OK
fwnode_handle_put(cs_fwnode);
}
}
/* set up a connection */
err = cti_add_connection_entry(dev, drvdata, tc, csdev, assoc_name);
+create_con_err:
return err;
+}
+static int cti_plat_create_impdef_connections(struct device *dev,
struct cti_drvdata *drvdata)
+{
int rc = 0;
struct fwnode_handle *fwnode = dev_fwnode(dev);
struct fwnode_handle *child = NULL;
if (IS_ERR_OR_NULL(fwnode))
return -EINVAL;
fwnode_for_each_child_node(fwnode, child) {
if (cti_plat_node_name_eq(child, CTI_DT_CONNS))
rc = cti_plat_create_connection(dev, drvdata, child);
if (rc != 0)
break;
minor nit: To make it more obvious :
if (cti_plat_node_name_eq(child, CTI_DT_CONNS)) { rc = cti_plat_create_connection(dev, drvdata, child); if (rc) break; }
Suzuki
Thanks
Mike
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
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 --- drivers/hwtracing/coresight/coresight-cti.c | 87 +++++++++++++++++++ .../hwtracing/coresight/coresight-platform.c | 23 +++++ drivers/hwtracing/coresight/coresight-priv.h | 6 ++ drivers/hwtracing/coresight/coresight.c | 58 +++++++++++-- include/linux/coresight.h | 5 ++ 5 files changed, 173 insertions(+), 6 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 369488dd7b8e..cf116463149a 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -440,6 +440,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) { @@ -574,6 +658,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(&drvdata->csdev->dev, "CTI initialized\n"); 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..484e5ec593bb 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -162,6 +162,12 @@ 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 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 1a5fdf2710ff..7657be009246 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; }
@@ -269,8 +299,15 @@ static int coresight_enable_link(struct coresight_device *csdev, if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && outport < 0) return outport;
- if (link_ops(csdev)->enable) - ret = link_ops(csdev)->enable(csdev, inport, outport); + if (link_ops(csdev)->enable) { + 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) csdev->enable = true;
@@ -300,8 +337,10 @@ static void coresight_disable_link(struct coresight_device *csdev, nr_conns = 1; }
- 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++) if (atomic_read(&csdev->refcnt[i]) != 0) @@ -322,9 +361,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; } @@ -347,6 +391,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; @@ -1252,6 +1297,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 b3e582d96a34..b5dc9baf0c58 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; };
/* @@ -341,5 +345,6 @@ static inline bool coresight_loses_context_with_cpu(struct device *dev) 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 Tue, Nov 19, 2019 at 11:19:06PM +0000, 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
drivers/hwtracing/coresight/coresight-cti.c | 87 +++++++++++++++++++ .../hwtracing/coresight/coresight-platform.c | 23 +++++ drivers/hwtracing/coresight/coresight-priv.h | 6 ++ drivers/hwtracing/coresight/coresight.c | 58 +++++++++++-- include/linux/coresight.h | 5 ++ 5 files changed, 173 insertions(+), 6 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 369488dd7b8e..cf116463149a 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -440,6 +440,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) { @@ -574,6 +658,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(&drvdata->csdev->dev, "CTI initialized\n");
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..484e5ec593bb 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -162,6 +162,12 @@ 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 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 1a5fdf2710ff..7657be009246 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");
Indentation problem - please replace with:
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;
Unneeded modification.
With the above changes: Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org
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;
} @@ -269,8 +299,15 @@ static int coresight_enable_link(struct coresight_device *csdev, if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && outport < 0) return outport;
- if (link_ops(csdev)->enable)
ret = link_ops(csdev)->enable(csdev, inport, outport);
- if (link_ops(csdev)->enable) {
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) csdev->enable = true;
@@ -300,8 +337,10 @@ static void coresight_disable_link(struct coresight_device *csdev, nr_conns = 1; }
- 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++) if (atomic_read(&csdev->refcnt[i]) != 0) @@ -322,9 +361,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; }};
@@ -347,6 +391,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);
@@ -1252,6 +1297,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 b3e582d96a34..b5dc9baf0c58 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;
}; /* @@ -341,5 +345,6 @@ static inline bool coresight_loses_context_with_cpu(struct device *dev) 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,
Will fix as requested.
Thanks
Mike
On Mon, 25 Nov 2019 at 22:45, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Tue, Nov 19, 2019 at 11:19:06PM +0000, 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
drivers/hwtracing/coresight/coresight-cti.c | 87 +++++++++++++++++++ .../hwtracing/coresight/coresight-platform.c | 23 +++++ drivers/hwtracing/coresight/coresight-priv.h | 6 ++ drivers/hwtracing/coresight/coresight.c | 58 +++++++++++-- include/linux/coresight.h | 5 ++ 5 files changed, 173 insertions(+), 6 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 369488dd7b8e..cf116463149a 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -440,6 +440,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) { @@ -574,6 +658,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(&drvdata->csdev->dev, "CTI initialized\n");
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..484e5ec593bb 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -162,6 +162,12 @@ 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 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 1a5fdf2710ff..7657be009246 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");
Indentation problem - please replace with:
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;
Unneeded modification.
With the above changes: Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org
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;
}
@@ -269,8 +299,15 @@ static int coresight_enable_link(struct coresight_device *csdev, if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && outport < 0) return outport;
if (link_ops(csdev)->enable)
ret = link_ops(csdev)->enable(csdev, inport, outport);
if (link_ops(csdev)->enable) {
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) csdev->enable = true;
@@ -300,8 +337,10 @@ static void coresight_disable_link(struct coresight_device *csdev, nr_conns = 1; }
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++) if (atomic_read(&csdev->refcnt[i]) != 0)
@@ -322,9 +361,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; }
@@ -347,6 +391,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;
@@ -1252,6 +1297,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 b3e582d96a34..b5dc9baf0c58 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;
};
/* @@ -341,5 +345,6 @@ static inline bool coresight_loses_context_with_cpu(struct device *dev) 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 19/11/2019 23:19, 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
drivers/hwtracing/coresight/coresight-cti.c | 87 +++++++++++++++++++ .../hwtracing/coresight/coresight-platform.c | 23 +++++ drivers/hwtracing/coresight/coresight-priv.h | 6 ++ drivers/hwtracing/coresight/coresight.c | 58 +++++++++++-- include/linux/coresight.h | 5 ++ 5 files changed, 173 insertions(+), 6 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 369488dd7b8e..cf116463149a 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -440,6 +440,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)
Here we actually fixup the name of the connection, rather than simply matching it. So it may be apt to rename this to cti_match_fixup_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)) {
Can there be duplicate node_name's ? Does it make sense to store the fwhandle along with the "temporary node_name" to match it later while fixing up ?
/* 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);
We used "cti_plat_get_node_name()" when we added the name in the absence of csdev in patch 7, could we not reuse the function here ?
- 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;
break; instead ?
}
- }
+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;
- }
Does this need to take the coresight_mutex to avoid racing against a coresight_enable_path() ? Though this may be fine as long as the CTI driver detects that that device was not enabled.
Also, it looks like we have a potential issue with perf vs sysfs mode. The perf mode doesn't seem to take the coresight_mutex, for build_path/enable_path operations. This is outside the scope of this series though.
+}
- /** cti ect operations **/ int cti_enable(struct coresight_device *csdev) {
@@ -574,6 +658,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(&drvdata->csdev->dev, "CTI initialized\n"); 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)
As mentioned above, please could we reuse the name helper we used during the insertion rather than introducing a new wrapper which effectively does the same thing ?
+{
- 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);
Why does this get exported ? If a following patch needs it, you may always do that when you need it.
Cheers Suzuki
On Fri, 29 Nov 2019 at 11:28, Suzuki Kuruppassery Poulose suzuki.poulose@arm.com wrote:
On 19/11/2019 23:19, 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
drivers/hwtracing/coresight/coresight-cti.c | 87 +++++++++++++++++++ .../hwtracing/coresight/coresight-platform.c | 23 +++++ drivers/hwtracing/coresight/coresight-priv.h | 6 ++ drivers/hwtracing/coresight/coresight.c | 58 +++++++++++-- include/linux/coresight.h | 5 ++ 5 files changed, 173 insertions(+), 6 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 369488dd7b8e..cf116463149a 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -440,6 +440,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)
Here we actually fixup the name of the connection, rather than simply matching it. So it may be apt to rename this to cti_match_fixup_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)) {
Can there be duplicate node_name's ? Does it make sense to store the fwhandle along with the "temporary node_name" to match it later while fixing up ?
I think we're fine here - CS devices have bidirectional connections that are checked by the DTC. You get a bitter complaint if two CS nodes have the same value.
/* 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);
We used "cti_plat_get_node_name()" when we added the name in the absence of csdev in patch 7, could we not reuse the function here ?
- 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;
break; instead ?
}
}
+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;
}
Does this need to take the coresight_mutex to avoid racing against a coresight_enable_path() ? Though this may be fine as long as the CTI driver detects that that device was not enabled.
Also, it looks like we have a potential issue with perf vs sysfs mode. The perf mode doesn't seem to take the coresight_mutex, for build_path/enable_path operations. This is outside the scope of this series though.
+}
- /** cti ect operations **/ int cti_enable(struct coresight_device *csdev) {
@@ -574,6 +658,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(&drvdata->csdev->dev, "CTI initialized\n");
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)
As mentioned above, please could we reuse the name helper we used during the insertion rather than introducing a new wrapper which effectively does the same thing ?
+{
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);
Why does this get exported ? If a following patch needs it, you may always do that when you need it.
Cheers Suzuki
Hi Suzuki
On Fri, 29 Nov 2019 at 18:28, Suzuki Kuruppassery Poulose suzuki.poulose@arm.com wrote:
On 19/11/2019 23:19, 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
drivers/hwtracing/coresight/coresight-cti.c | 87 +++++++++++++++++++ .../hwtracing/coresight/coresight-platform.c | 23 +++++ drivers/hwtracing/coresight/coresight-priv.h | 6 ++ drivers/hwtracing/coresight/coresight.c | 58 +++++++++++-- include/linux/coresight.h | 5 ++ 5 files changed, 173 insertions(+), 6 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 369488dd7b8e..cf116463149a 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -440,6 +440,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)
Here we actually fixup the name of the connection, rather than simply matching it. So it may be apt to rename this to cti_match_fixup_name()
Agreed.
+{
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)) {
Can there be duplicate node_name's ? Does it make sense to store the fwhandle along with the "temporary node_name" to match it later while fixing up ?
/* 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);
We used "cti_plat_get_node_name()" when we added the name in the absence of csdev in patch 7, could we not reuse the function here ?
Agreed - I'll remove the superfluous function.
- 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;
break; instead ?
}
}
+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;
}
Does this need to take the coresight_mutex to avoid racing against a coresight_enable_path() ? Though this may be fine as long as the CTI driver detects that that device was not enabled.
Given this happens during probe, normally before trace is being enabled this seems unlikely. That said - the converse function happens inside the mutex, so this should too.
Also, it looks like we have a potential issue with perf vs sysfs mode. The perf mode doesn't seem to take the coresight_mutex, for build_path/enable_path operations. This is outside the scope of this series though.
+}
- /** cti ect operations **/ int cti_enable(struct coresight_device *csdev) {
@@ -574,6 +658,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(&drvdata->csdev->dev, "CTI initialized\n");
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)
As mentioned above, please could we reuse the name helper we used during the insertion rather than introducing a new wrapper which effectively does the same thing ?
Agreed.
+{
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);
Why does this get exported ? If a following patch needs it, you may always do that when you need it.
Cheers Suzuki
Thanks
Mike
-- 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 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 | 376 +++++++++++++++++- drivers/hwtracing/coresight/coresight-cti.c | 13 +- drivers/hwtracing/coresight/coresight-cti.h | 11 +- 3 files changed, 396 insertions(+), 4 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index f800402f73da..91986732506f 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -8,6 +8,67 @@
#include "coresight-cti.h"
+/* + * Declare the number of static declared attribute groups + * Value includes groups + NULL value at end of table. + */ +#define CORESIGHT_CTI_STATIC_GROUPS_MAX 5 + +/* + * List of trigger signal type names. Match the constants declared in + * include\dt-bindings\arm\coresight-cti-dt.h + */ +static const char * const sig_type_names[] = { + "genio", /* GEN_IO */ + "intreq", /* GEN_INTREQ */ + "intack", /* GEN_INTACK */ + "haltreq", /* GEN_HALTREQ */ + "restartreq", /* GEN_RESTARTREQ */ + "pe_edbgreq", /* PE_EDBGREQ */ + "pe_dbgrestart",/* PE_DBGRESTART */ + "pe_ctiirq", /* PE_CTIIRQ */ + "pe_pmuirq", /* PE_PMUIRQ */ + "pe_dbgtrigger",/* PE_DBGTRIGGER */ + "etm_extout", /* ETM_EXTOUT */ + "etm_extin", /* ETM_EXTIN */ + "snk_full", /* SNK_FULL */ + "snk_acqcomp", /* SNK_ACQCOMP */ + "snk_flushcomp",/* SNK_FLUSHCOMP */ + "snk_flushin", /* SNK_FLUSHIN */ + "snk_trigin", /* SNK_TRIGIN */ + "stm_asyncout", /* STM_ASYNCOUT */ + "stm_tout_spte",/* STM_TOUT_SPTE */ + "stm_tout_sw", /* STM_TOUT_SW */ + "stm_tout_hete",/* STM_TOUT_HETE */ + "stm_hwevent", /* STM_HWEVENT */ + "ela_tstart", /* ELA_TSTART */ + "ela_tstop", /* ELA_TSTOP */ + "ela_dbgreq", /* ELA_DBGREQ */ +}; + +/* Show function pointer used in the connections dynamic declared attributes*/ +typedef ssize_t (*p_show_fn)(struct device *dev, struct device_attribute *attr, + char *buf); + +/* Connection attribute types */ +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, + CTI_CON_ATTR_MAX, +}; + +/* Names for the connection attributes */ +static const char * const con_attr_names[CTI_CON_ATTR_MAX] = { + "name", + "in_signals", + "out_signals", + "in_types", + "out_types", +}; + /* basic attributes */ static ssize_t enable_show(struct device *dev, struct device_attribute *attr, @@ -66,10 +127,21 @@ static ssize_t ctmid_show(struct device *dev, } static DEVICE_ATTR_RO(ctmid);
+static ssize_t nr_trigger_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_trigger_cons); + /* attribute and group sysfs tables. */ static struct attribute *coresight_cti_attrs[] = { &dev_attr_enable.attr, &dev_attr_ctmid.attr, + &dev_attr_nr_trigger_cons.attr, NULL, };
@@ -818,7 +890,306 @@ static struct attribute *coresight_cti_channel_attrs[] = { NULL, };
-/* sysfs groups */ +/* Create the connections trigger groups and attrs dynamically */ +/* + * Each connection has dynamic group triggers<N> + name, trigin/out sigs/types + * attributes, + each device has static nr_trigger_cons giving the number + * of groups. e.g. in sysfs:- + * /cti_<name>/triggers0 + * /cti_<name>/triggers1 + * /cti_<name>/nr_trigger_cons + * where nr_trigger_cons = 2 + */ +static ssize_t con_name_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dev_ext_attribute *ext_attr = + container_of(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 = + container_of(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 = + container_of(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) +{ + 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 = + container_of(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 = + container_of(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; +} + +/* + * Array of show function names declared above to allow selection + * for the connection attributes + */ +static p_show_fn show_fns[CTI_CON_ATTR_MAX] = { + con_name_show, + trigin_sig_show, + trigout_sig_show, + trigin_type_show, + trigout_type_show, +}; + +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 = kstrdup(con_attr_names[attr_type], GFP_KERNEL); + if (name) { + /* fill out the underlying attribute struct */ + 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->attr.attr; + return 0; +} + +static struct attribute_group * +cti_create_con_sysfs_group(struct cti_device *ctidev, int con_idx, + struct cti_trig_con *con) +{ + 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 + CORESIGHT_CTI_STATIC_GROUPS_MAX - 1] + = group; + con->attr_group = group; + return group; +} + +/* 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, con); + if (!attr_group) + return -ENOMEM; + + /* allocate NULL terminated array of attributes */ + con->con_attrs = kcalloc(CTI_CON_ATTR_MAX + 1, + sizeof(struct 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 = 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 + CORESIGHT_CTI_STATIC_GROUPS_MAX; + 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 < (CORESIGHT_CTI_STATIC_GROUPS_MAX - 1); 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_free_con_attr(struct attribute *con_attr) +{ + struct device_attribute *dattr = + container_of(con_attr, struct device_attribute, attr); + struct dev_ext_attribute *dev_ext_attr = + container_of(dattr, struct dev_ext_attribute, attr); + kfree(con_attr->name); + kfree(dev_ext_attr); +} + +void cti_free_con_group(struct attribute_group *attr_group) +{ + if (attr_group) { + kfree(attr_group->name); + kfree(attr_group); + } +} + +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_CON_ATTR_MAX; i++) { + if (con->con_attrs[i]) + cti_free_con_attr(con->con_attrs[i]); + } + kfree(con->con_attrs); + } + cti_free_con_group(con->attr_group); +} + +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, }; @@ -838,7 +1209,8 @@ static const struct attribute_group coresight_cti_channels_group = { .name = "channels", };
-const struct attribute_group *coresight_cti_groups[] = { +const struct attribute_group * +coresight_cti_groups[CORESIGHT_CTI_STATIC_GROUPS_MAX] = { &coresight_cti_group, &coresight_cti_mgmt_group, &coresight_cti_regs_group, diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index cf116463149a..c3d63cc53bdd 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -561,6 +561,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) { @@ -636,12 +639,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 9a22f6fcad65..dc5b265acf5e 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -74,6 +74,8 @@ 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. + * @attr_group: Dynamic attribute group created for this connection. */ struct cti_trig_con { struct cti_trig_grp *con_in; @@ -81,6 +83,8 @@ struct cti_trig_con { struct coresight_device *con_dev; char *con_dev_name; struct list_head node; + struct attribute **con_attrs; + struct attribute_group *attr_group; };
/** @@ -91,12 +95,15 @@ 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: combined static and 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; };
/** @@ -111,7 +118,7 @@ struct cti_device { * @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 + * 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. @@ -214,6 +221,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);
On Tue, Nov 19, 2019 at 11:19:07PM +0000, 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 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 | 376 +++++++++++++++++- drivers/hwtracing/coresight/coresight-cti.c | 13 +- drivers/hwtracing/coresight/coresight-cti.h | 11 +- 3 files changed, 396 insertions(+), 4 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index f800402f73da..91986732506f 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -8,6 +8,67 @@ #include "coresight-cti.h" +/*
- Declare the number of static declared attribute groups
- Value includes groups + NULL value at end of table.
- */
+#define CORESIGHT_CTI_STATIC_GROUPS_MAX 5
+/*
- List of trigger signal type names. Match the constants declared in
- include\dt-bindings\arm\coresight-cti-dt.h
- */
+static const char * const sig_type_names[] = {
- "genio", /* GEN_IO */
- "intreq", /* GEN_INTREQ */
- "intack", /* GEN_INTACK */
- "haltreq", /* GEN_HALTREQ */
- "restartreq", /* GEN_RESTARTREQ */
- "pe_edbgreq", /* PE_EDBGREQ */
- "pe_dbgrestart",/* PE_DBGRESTART */
- "pe_ctiirq", /* PE_CTIIRQ */
- "pe_pmuirq", /* PE_PMUIRQ */
- "pe_dbgtrigger",/* PE_DBGTRIGGER */
- "etm_extout", /* ETM_EXTOUT */
- "etm_extin", /* ETM_EXTIN */
- "snk_full", /* SNK_FULL */
- "snk_acqcomp", /* SNK_ACQCOMP */
- "snk_flushcomp",/* SNK_FLUSHCOMP */
- "snk_flushin", /* SNK_FLUSHIN */
- "snk_trigin", /* SNK_TRIGIN */
- "stm_asyncout", /* STM_ASYNCOUT */
- "stm_tout_spte",/* STM_TOUT_SPTE */
- "stm_tout_sw", /* STM_TOUT_SW */
- "stm_tout_hete",/* STM_TOUT_HETE */
- "stm_hwevent", /* STM_HWEVENT */
- "ela_tstart", /* ELA_TSTART */
- "ela_tstop", /* ELA_TSTOP */
- "ela_dbgreq", /* ELA_DBGREQ */
+};
+/* Show function pointer used in the connections dynamic declared attributes*/ +typedef ssize_t (*p_show_fn)(struct device *dev, struct device_attribute *attr,
char *buf);
+/* Connection attribute types */ +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,
- CTI_CON_ATTR_MAX,
+};
+/* Names for the connection attributes */ +static const char * const con_attr_names[CTI_CON_ATTR_MAX] = {
- "name",
- "in_signals",
- "out_signals",
- "in_types",
- "out_types",
+};
/* basic attributes */ static ssize_t enable_show(struct device *dev, struct device_attribute *attr, @@ -66,10 +127,21 @@ static ssize_t ctmid_show(struct device *dev, } static DEVICE_ATTR_RO(ctmid); +static ssize_t nr_trigger_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_trigger_cons);
/* attribute and group sysfs tables. */ static struct attribute *coresight_cti_attrs[] = { &dev_attr_enable.attr, &dev_attr_ctmid.attr,
- &dev_attr_nr_trigger_cons.attr,
I think it looks much getter that way - thanks for moving that.
NULL, }; @@ -818,7 +890,306 @@ static struct attribute *coresight_cti_channel_attrs[] = { NULL, }; -/* sysfs groups */ +/* Create the connections trigger groups and attrs dynamically */ +/*
- Each connection has dynamic group triggers<N> + name, trigin/out sigs/types
- attributes, + each device has static nr_trigger_cons giving the number
- of groups. e.g. in sysfs:-
- /cti_<name>/triggers0
- /cti_<name>/triggers1
- /cti_<name>/nr_trigger_cons
- where nr_trigger_cons = 2
- */
+static ssize_t con_name_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct dev_ext_attribute *ext_attr =
container_of(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 =
container_of(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 =
container_of(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) +{
- 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 =
container_of(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 =
container_of(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;
+}
+/*
- Array of show function names declared above to allow selection
- for the connection attributes
- */
+static p_show_fn show_fns[CTI_CON_ATTR_MAX] = {
- con_name_show,
- trigin_sig_show,
- trigout_sig_show,
- trigin_type_show,
- trigout_type_show,
+};
+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 = kstrdup(con_attr_names[attr_type], GFP_KERNEL);
if (name) {
/* fill out the underlying attribute struct */
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->attr.attr;
- return 0;
+}
+static struct attribute_group * +cti_create_con_sysfs_group(struct cti_device *ctidev, int con_idx,
struct cti_trig_con *con)
+{
- 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 + CORESIGHT_CTI_STATIC_GROUPS_MAX - 1]
= group;
idx = con_idx + CORESIGHT_CTI_STATIC_GROUPS_MAX - 1; ctidev->con_groups[idx] = group;
- con->attr_group = group;
- return group;
+}
+/* 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, con);
- if (!attr_group)
return -ENOMEM;
- /* allocate NULL terminated array of attributes */
- con->con_attrs = kcalloc(CTI_CON_ATTR_MAX + 1,
sizeof(struct 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) {
I think we should check the validity of con->con_in before proceeding, especially if people can do their HW however they want. Same for con->con_out below.
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) {
if (con->con_out->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 = 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 + CORESIGHT_CTI_STATIC_GROUPS_MAX;
- 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 < (CORESIGHT_CTI_STATIC_GROUPS_MAX - 1); 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_free_con_attr(struct attribute *con_attr) +{
- struct device_attribute *dattr =
container_of(con_attr, struct device_attribute, attr);
- struct dev_ext_attribute *dev_ext_attr =
container_of(dattr, struct dev_ext_attribute, attr);
- kfree(con_attr->name);
- kfree(dev_ext_attr);
+}
+void cti_free_con_group(struct attribute_group *attr_group) +{
- if (attr_group) {
kfree(attr_group->name);
kfree(attr_group);
- }
+}
+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_CON_ATTR_MAX; i++) {
if (con->con_attrs[i])
cti_free_con_attr(con->con_attrs[i]);
}
kfree(con->con_attrs);
- }
- cti_free_con_group(con->attr_group);
+}
+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, }; @@ -838,7 +1209,8 @@ static const struct attribute_group coresight_cti_channels_group = { .name = "channels", }; -const struct attribute_group *coresight_cti_groups[] = { +const struct attribute_group * +coresight_cti_groups[CORESIGHT_CTI_STATIC_GROUPS_MAX] = { &coresight_cti_group, &coresight_cti_mgmt_group, &coresight_cti_regs_group, diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index cf116463149a..c3d63cc53bdd 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -561,6 +561,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) {
@@ -636,12 +639,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 9a22f6fcad65..dc5b265acf5e 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -74,6 +74,8 @@ 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.
*/
- @attr_group: Dynamic attribute group created for this connection.
struct cti_trig_con { struct cti_trig_grp *con_in; @@ -81,6 +83,8 @@ struct cti_trig_con { struct coresight_device *con_dev; char *con_dev_name; struct list_head node;
- struct attribute **con_attrs;
- struct attribute_group *attr_group;
}; /** @@ -91,12 +95,15 @@ 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: combined static and 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;
}; /** @@ -111,7 +118,7 @@ struct cti_device {
- @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
enabled. Typically this would be dbgreq / restart on
Spurious change.
With the above: Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org
a core CTI.
- @trig_filter_enable: 1 if filtering enabled.
- @xtrig_rchan_sel: channel selection for xtrigger connection show.
@@ -214,6 +221,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); -- 2.17.1
Hi Mathieu,
On Wed, 27 Nov 2019 at 18:09, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Tue, Nov 19, 2019 at 11:19:07PM +0000, 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 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 | 376 +++++++++++++++++- drivers/hwtracing/coresight/coresight-cti.c | 13 +- drivers/hwtracing/coresight/coresight-cti.h | 11 +- 3 files changed, 396 insertions(+), 4 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index f800402f73da..91986732506f 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -8,6 +8,67 @@
#include "coresight-cti.h"
+/*
- Declare the number of static declared attribute groups
- Value includes groups + NULL value at end of table.
- */
+#define CORESIGHT_CTI_STATIC_GROUPS_MAX 5
+/*
- List of trigger signal type names. Match the constants declared in
- include\dt-bindings\arm\coresight-cti-dt.h
- */
+static const char * const sig_type_names[] = {
"genio", /* GEN_IO */
"intreq", /* GEN_INTREQ */
"intack", /* GEN_INTACK */
"haltreq", /* GEN_HALTREQ */
"restartreq", /* GEN_RESTARTREQ */
"pe_edbgreq", /* PE_EDBGREQ */
"pe_dbgrestart",/* PE_DBGRESTART */
"pe_ctiirq", /* PE_CTIIRQ */
"pe_pmuirq", /* PE_PMUIRQ */
"pe_dbgtrigger",/* PE_DBGTRIGGER */
"etm_extout", /* ETM_EXTOUT */
"etm_extin", /* ETM_EXTIN */
"snk_full", /* SNK_FULL */
"snk_acqcomp", /* SNK_ACQCOMP */
"snk_flushcomp",/* SNK_FLUSHCOMP */
"snk_flushin", /* SNK_FLUSHIN */
"snk_trigin", /* SNK_TRIGIN */
"stm_asyncout", /* STM_ASYNCOUT */
"stm_tout_spte",/* STM_TOUT_SPTE */
"stm_tout_sw", /* STM_TOUT_SW */
"stm_tout_hete",/* STM_TOUT_HETE */
"stm_hwevent", /* STM_HWEVENT */
"ela_tstart", /* ELA_TSTART */
"ela_tstop", /* ELA_TSTOP */
"ela_dbgreq", /* ELA_DBGREQ */
+};
+/* Show function pointer used in the connections dynamic declared attributes*/ +typedef ssize_t (*p_show_fn)(struct device *dev, struct device_attribute *attr,
char *buf);
+/* Connection attribute types */ +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,
CTI_CON_ATTR_MAX,
+};
+/* Names for the connection attributes */ +static const char * const con_attr_names[CTI_CON_ATTR_MAX] = {
"name",
"in_signals",
"out_signals",
"in_types",
"out_types",
+};
/* basic attributes */ static ssize_t enable_show(struct device *dev, struct device_attribute *attr, @@ -66,10 +127,21 @@ static ssize_t ctmid_show(struct device *dev, } static DEVICE_ATTR_RO(ctmid);
+static ssize_t nr_trigger_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_trigger_cons);
/* attribute and group sysfs tables. */ static struct attribute *coresight_cti_attrs[] = { &dev_attr_enable.attr, &dev_attr_ctmid.attr,
&dev_attr_nr_trigger_cons.attr,
I think it looks much getter that way - thanks for moving that.
NULL,
};
@@ -818,7 +890,306 @@ static struct attribute *coresight_cti_channel_attrs[] = { NULL, };
-/* sysfs groups */ +/* Create the connections trigger groups and attrs dynamically */ +/*
- Each connection has dynamic group triggers<N> + name, trigin/out sigs/types
- attributes, + each device has static nr_trigger_cons giving the number
- of groups. e.g. in sysfs:-
- /cti_<name>/triggers0
- /cti_<name>/triggers1
- /cti_<name>/nr_trigger_cons
- where nr_trigger_cons = 2
- */
+static ssize_t con_name_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
struct dev_ext_attribute *ext_attr =
container_of(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 =
container_of(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 =
container_of(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) +{
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 =
container_of(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 =
container_of(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;
+}
+/*
- Array of show function names declared above to allow selection
- for the connection attributes
- */
+static p_show_fn show_fns[CTI_CON_ATTR_MAX] = {
con_name_show,
trigin_sig_show,
trigout_sig_show,
trigin_type_show,
trigout_type_show,
+};
+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 = kstrdup(con_attr_names[attr_type], GFP_KERNEL);
if (name) {
/* fill out the underlying attribute struct */
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->attr.attr;
return 0;
+}
+static struct attribute_group * +cti_create_con_sysfs_group(struct cti_device *ctidev, int con_idx,
struct cti_trig_con *con)
+{
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 + CORESIGHT_CTI_STATIC_GROUPS_MAX - 1]
= group;
idx = con_idx + CORESIGHT_CTI_STATIC_GROUPS_MAX - 1; ctidev->con_groups[idx] = group;
OK
con->attr_group = group;
return group;
+}
+/* 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, con);
if (!attr_group)
return -ENOMEM;
/* allocate NULL terminated array of attributes */
con->con_attrs = kcalloc(CTI_CON_ATTR_MAX + 1,
sizeof(struct 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) {
I think we should check the validity of con->con_in before proceeding, especially if people can do their HW however they want. Same for con->con_out below.
When we create con, we also create con->con_in and con->con_out as zero init. So this is safe and all the handling code is much simpler. The implementation dependent issues are thus handled in the con_in / con_out structure attribute values.
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) {
if (con->con_out->nr_sigs > 0)
Good spot!
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 = 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 + CORESIGHT_CTI_STATIC_GROUPS_MAX;
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 < (CORESIGHT_CTI_STATIC_GROUPS_MAX - 1); 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_free_con_attr(struct attribute *con_attr) +{
struct device_attribute *dattr =
container_of(con_attr, struct device_attribute, attr);
struct dev_ext_attribute *dev_ext_attr =
container_of(dattr, struct dev_ext_attribute, attr);
kfree(con_attr->name);
kfree(dev_ext_attr);
+}
+void cti_free_con_group(struct attribute_group *attr_group) +{
if (attr_group) {
kfree(attr_group->name);
kfree(attr_group);
}
+}
+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_CON_ATTR_MAX; i++) {
if (con->con_attrs[i])
cti_free_con_attr(con->con_attrs[i]);
}
kfree(con->con_attrs);
}
cti_free_con_group(con->attr_group);
+}
+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, }; @@ -838,7 +1209,8 @@ static const struct attribute_group coresight_cti_channels_group = { .name = "channels", };
-const struct attribute_group *coresight_cti_groups[] = { +const struct attribute_group * +coresight_cti_groups[CORESIGHT_CTI_STATIC_GROUPS_MAX] = { &coresight_cti_group, &coresight_cti_mgmt_group, &coresight_cti_regs_group, diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index cf116463149a..c3d63cc53bdd 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -561,6 +561,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) {
@@ -636,12 +639,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 9a22f6fcad65..dc5b265acf5e 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -74,6 +74,8 @@ 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.
*/
- @attr_group: Dynamic attribute group created for this connection.
struct cti_trig_con { struct cti_trig_grp *con_in; @@ -81,6 +83,8 @@ struct cti_trig_con { struct coresight_device *con_dev; char *con_dev_name; struct list_head node;
struct attribute **con_attrs;
struct attribute_group *attr_group;
};
/** @@ -91,12 +95,15 @@ 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: combined static and 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;
};
/** @@ -111,7 +118,7 @@ struct cti_device {
- @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
enabled. Typically this would be dbgreq / restart on
Spurious change.
Looks like a whitespace issue - will address in earlier patch.
With the above: Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org
a core CTI.
- @trig_filter_enable: 1 if filtering enabled.
- @xtrig_rchan_sel: channel selection for xtrigger connection show.
@@ -214,6 +221,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);
-- 2.17.1
Thanks
Mike
On 19/11/2019 23:19, 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 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 | 376 +++++++++++++++++- drivers/hwtracing/coresight/coresight-cti.c | 13 +- drivers/hwtracing/coresight/coresight-cti.h | 11 +- 3 files changed, 396 insertions(+), 4 deletions(-)
The patch looks good overall, some minor comments below.
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index f800402f73da..91986732506f 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -8,6 +8,67 @@
@@ -818,7 +890,306 @@ static struct attribute *coresight_cti_channel_attrs[] = { NULL, }; -/* sysfs groups */ +/* Create the connections trigger groups and attrs dynamically */ +/*
- Each connection has dynamic group triggers<N> + name, trigin/out sigs/types
- attributes, + each device has static nr_trigger_cons giving the number
- of groups. e.g. in sysfs:-
- /cti_<name>/triggers0
- /cti_<name>/triggers1
- /cti_<name>/nr_trigger_cons
- where nr_trigger_cons = 2
- */
+static ssize_t con_name_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct dev_ext_attribute *ext_attr =
container_of(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 =
container_of(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 =
container_of(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) +{
- 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 =
container_of(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 =
container_of(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;
+}
+/*
- Array of show function names declared above to allow selection
- for the connection attributes
- */
+static p_show_fn show_fns[CTI_CON_ATTR_MAX] = {
- con_name_show,
- trigin_sig_show,
- trigout_sig_show,
- trigin_type_show,
- trigout_type_show,
+};
+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;
super minor nit: You may use "eattr" instead.
- char *name = 0;
- dev_ext_attr = kzalloc(sizeof(struct dev_ext_attribute), GFP_KERNEL);
Could we not use devm_* alloc helpers everywhere ?
- if (dev_ext_attr) {
name = kstrdup(con_attr_names[attr_type], GFP_KERNEL);
if (name) {
/* fill out the underlying attribute struct */
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->attr.attr;
- return 0;
+}
+static struct attribute_group * +cti_create_con_sysfs_group(struct cti_device *ctidev, int con_idx,
struct cti_trig_con *con)
+{
- 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 + CORESIGHT_CTI_STATIC_GROUPS_MAX - 1]
= group;
nit: con_idx += CORESIGHT_CTI_STATIC_GROUPS_MAX - 1; ctidev->con_groups[con_idx] = group;
- con->attr_group = group;
- return group;
+}
+/* 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, con);
- if (!attr_group)
return -ENOMEM;
- /* allocate NULL terminated array of attributes */
- con->con_attrs = kcalloc(CTI_CON_ATTR_MAX + 1,
sizeof(struct attribute *),
GFP_KERNEL);
Again why not devm_* allocations ? That takes the pain of freeing the memory away and helps prevent memory leaks.
- 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 = 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 + CORESIGHT_CTI_STATIC_GROUPS_MAX;
- 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 < (CORESIGHT_CTI_STATIC_GROUPS_MAX - 1); i++)
ctidev->con_groups[i] = coresight_cti_groups[i];
- return 0;
+}
To be frank, it doesn't make sense to have this split of populating the groups.
+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_free_con_attr(struct attribute *con_attr) +{
- struct device_attribute *dattr =
container_of(con_attr, struct device_attribute, attr);
- struct dev_ext_attribute *dev_ext_attr =
container_of(dattr, struct dev_ext_attribute, attr);
- kfree(con_attr->name);
- kfree(dev_ext_attr);
+}
+void cti_free_con_group(struct attribute_group *attr_group) +{
- if (attr_group) {
kfree(attr_group->name);
kfree(attr_group);
- }
+}
+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_CON_ATTR_MAX; i++) {
if (con->con_attrs[i])
cti_free_con_attr(con->con_attrs[i]);
}
kfree(con->con_attrs);
- }
- cti_free_con_group(con->attr_group);
+}
+void cti_destroy_cons_sysfs(struct cti_device *ctidev) +{
- struct cti_trig_con *tc;
minor nit: Please keep the variable name consistent if possible, helps a lot with the code following. i.e, tc vs con above in cti_destroy_cons_attr_set().
- 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, }; @@ -838,7 +1209,8 @@ static const struct attribute_group coresight_cti_channels_group = { .name = "channels", }; -const struct attribute_group *coresight_cti_groups[] = { +const struct attribute_group * +coresight_cti_groups[CORESIGHT_CTI_STATIC_GROUPS_MAX] = { &coresight_cti_group, &coresight_cti_mgmt_group, &coresight_cti_regs_group, diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index cf116463149a..c3d63cc53bdd 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -561,6 +561,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) {
@@ -636,12 +639,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);
nit: It may be a good idea to include the actual device name (rather than just cti_xxx). so may be :
dev_err(dev, "%s:....", cti_desc.name) ?
goto err_out;
- }
Except for the devm_ alloc question, rest are fine.
Suzuki
Hi suzuki,
On Mon, 2 Dec 2019 at 09:48, Suzuki Kuruppassery Poulose suzuki.poulose@arm.com wrote:
On 19/11/2019 23:19, 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 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 | 376 +++++++++++++++++- drivers/hwtracing/coresight/coresight-cti.c | 13 +- drivers/hwtracing/coresight/coresight-cti.h | 11 +- 3 files changed, 396 insertions(+), 4 deletions(-)
The patch looks good overall, some minor comments below.
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index f800402f73da..91986732506f 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -8,6 +8,67 @@
@@ -818,7 +890,306 @@ static struct attribute *coresight_cti_channel_attrs[] = { NULL, };
-/* sysfs groups */ +/* Create the connections trigger groups and attrs dynamically */ +/*
- Each connection has dynamic group triggers<N> + name, trigin/out sigs/types
- attributes, + each device has static nr_trigger_cons giving the number
- of groups. e.g. in sysfs:-
- /cti_<name>/triggers0
- /cti_<name>/triggers1
- /cti_<name>/nr_trigger_cons
- where nr_trigger_cons = 2
- */
+static ssize_t con_name_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
struct dev_ext_attribute *ext_attr =
container_of(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 =
container_of(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 =
container_of(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) +{
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 =
container_of(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 =
container_of(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;
+}
+/*
- Array of show function names declared above to allow selection
- for the connection attributes
- */
+static p_show_fn show_fns[CTI_CON_ATTR_MAX] = {
con_name_show,
trigin_sig_show,
trigout_sig_show,
trigin_type_show,
trigout_type_show,
+};
+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;
super minor nit: You may use "eattr" instead.
char *name = 0;
dev_ext_attr = kzalloc(sizeof(struct dev_ext_attribute), GFP_KERNEL);
Could we not use devm_* alloc helpers everywhere ?
Yes - will change.
if (dev_ext_attr) {
name = kstrdup(con_attr_names[attr_type], GFP_KERNEL);
if (name) {
/* fill out the underlying attribute struct */
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->attr.attr;
return 0;
+}
+static struct attribute_group * +cti_create_con_sysfs_group(struct cti_device *ctidev, int con_idx,
struct cti_trig_con *con)
+{
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 + CORESIGHT_CTI_STATIC_GROUPS_MAX - 1]
= group;
nit: con_idx += CORESIGHT_CTI_STATIC_GROUPS_MAX - 1; ctidev->con_groups[con_idx] = group;
OK.
con->attr_group = group;
return group;
+}
+/* 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, con);
if (!attr_group)
return -ENOMEM;
/* allocate NULL terminated array of attributes */
con->con_attrs = kcalloc(CTI_CON_ATTR_MAX + 1,
sizeof(struct attribute *),
GFP_KERNEL);
Again why not devm_* allocations ? That takes the pain of freeing the memory away and helps prevent memory leaks.
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 = 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 + CORESIGHT_CTI_STATIC_GROUPS_MAX;
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 < (CORESIGHT_CTI_STATIC_GROUPS_MAX - 1); i++)
ctidev->con_groups[i] = coresight_cti_groups[i];
return 0;
+}
To be frank, it doesn't make sense to have this split of populating the groups.
Moved to caller.
+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_free_con_attr(struct attribute *con_attr) +{
struct device_attribute *dattr =
container_of(con_attr, struct device_attribute, attr);
struct dev_ext_attribute *dev_ext_attr =
container_of(dattr, struct dev_ext_attribute, attr);
kfree(con_attr->name);
kfree(dev_ext_attr);
+}
+void cti_free_con_group(struct attribute_group *attr_group) +{
if (attr_group) {
kfree(attr_group->name);
kfree(attr_group);
}
+}
+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_CON_ATTR_MAX; i++) {
if (con->con_attrs[i])
cti_free_con_attr(con->con_attrs[i]);
}
kfree(con->con_attrs);
}
cti_free_con_group(con->attr_group);
+}
+void cti_destroy_cons_sysfs(struct cti_device *ctidev) +{
struct cti_trig_con *tc;
minor nit: Please keep the variable name consistent if possible, helps a lot with the code following. i.e, tc vs con above in cti_destroy_cons_attr_set().
OK
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, }; @@ -838,7 +1209,8 @@ static const struct attribute_group coresight_cti_channels_group = { .name = "channels", };
-const struct attribute_group *coresight_cti_groups[] = { +const struct attribute_group * +coresight_cti_groups[CORESIGHT_CTI_STATIC_GROUPS_MAX] = { &coresight_cti_group, &coresight_cti_mgmt_group, &coresight_cti_regs_group, diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index cf116463149a..c3d63cc53bdd 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -561,6 +561,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) {
@@ -636,12 +639,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);
nit: It may be a good idea to include the actual device name (rather than just cti_xxx). so may be :
dev_err(dev, "%s:....", cti_desc.name) ?
goto err_out;
}
Except for the devm_ alloc question, rest are fine.
Suzuki
Thanks
Mike
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 Tue, Nov 19, 2019 at 11:19:08PM +0000, 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";
};
/* 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>;
};
This looks good to me. Since Andy Gross maintains this file you will have to CC him on your next revision. Right now chances are he hasn't see it.
venus: video-codec@1d00000 { compatible = "qcom,msm8916-venus"; reg = <0x01d00000 0xff000>;
-- 2.17.1
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 | 150 +++++++++++++++++++++- 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, 251 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..4db2eca87dbf 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,88 @@ }; };
+ 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>; +};
On Tue, Nov 19, 2019 at 11:19:09PM +0000, Mike Leach wrote:
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 | 150 +++++++++++++++++++++- 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, 251 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..4db2eca87dbf 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,88 @@ }; };
- 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>;
+};
Same comment for these files - Liviu, Sudeep and Lorenzo will need to be CC'ed.
-- 2.17.1
Adds in CTI device tree information for the Hikey620 board.
Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org Tested-by: Leo Yan leo.yan@linaro.org Signed-off-by: Mike Leach mike.leach@linaro.org --- .../boot/dts/hisilicon/hi6220-coresight.dtsi | 130 ++++++++++++++++-- 1 file changed, 122 insertions(+), 8 deletions(-)
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>; + }; }; };
Add new document covering CTI / CTM usage in CoreSight.
Add section in coresight.rst introducing CTI and CTM modules with link to new document.
Signed-off-by: Mike Leach mike.leach@linaro.org --- .../trace/coresight/coresight-ect.rst | 200 ++++++++++++++++++ Documentation/trace/coresight/coresight.rst | 13 ++ 2 files changed, 213 insertions(+) create mode 100644 Documentation/trace/coresight/coresight-ect.rst
diff --git a/Documentation/trace/coresight/coresight-ect.rst b/Documentation/trace/coresight/coresight-ect.rst new file mode 100644 index 000000000000..6448cf910f20 --- /dev/null +++ b/Documentation/trace/coresight/coresight-ect.rst @@ -0,0 +1,200 @@ +============================================= +CoreSight Embedded Cross Trigger (CTI & CTM). +============================================= + + :Author: Mike Leach mike.leach@linaro.org + :Date: November 2019 + +Hardware Description +-------------------- + +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. + +Sysfs files and directories +--------------------------- + +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 ctmid enable nr_trigger_cons 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. + * ``nr_trigger_cons`` : total connections - triggers<N> directories. + +*Sub-directories:-* + * ``triggers<N>``: contains list of triggers for an individual connection. + * ``channels``: Contains the channel API - CTI main programming interface. + * ``regs``: Gives access to the raw programmable CTI regs. + * ``mgmt``: the standard CoreSight management registers. + + +triggers<N> directories +~~~~~~~~~~~~~~~~~~~~~~~ + +Individual trigger connection information. This describes trigger signals for +CoreSight and non-CoreSight 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 Directory +~~~~~~~~~~~~~~~~~~~~~~ + +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. + +A number of files provide this API:: + + >$ ls ./cti_sys0/channels/ + chan_clear chan_inuse chan_xtrigs_view trigin_detach + chan_free chan_pulse chan_xtrigs_view_sel trigout_attach + chan_gate_disable chan_set trig_filter_enable trigout_detach + chan_gate_enable chan_xtrigs_reset trigin_attach trigout_filtered + +Most access to these elements take the form:: + + echo <chan> [<trigger>] > /<device_path>/<operation> + +where the optional <trigger> is only needed for trigXX_attach | detach +operations. + +e.g.:: + + >$ echo 0 1 > ./cti_sys0/channels/trigout_attach + >$ echo 0 > ./cti_sys0/channels/chan_set + +Attaches trigout(1) to channel(0), then activates channel(0) generating a +set state on cti_sys0.trigout(1) + + +*API operations* + + * ``trigin_attach, trigout_attach``: Attach a channel to a trigger signal. + * ``trigin_detach, trigout_detach``: Detach a channel from a trigger signal. + * ``chan_set``: Set the channel - the set state will be propogated around + the CTM to other connected devices. + * ``chan_clear``: Clear the channel. + * ``chan_pulse``: Set the channel for a single CoreSight clock cycle. + * ``chan_gate_enable``: Write operation sets the CTI gate to propagate + (enable) the channel to other devices. This operation takes a channel + number. CTI gate is enabled for all channels by default at power up. Read + to list the currently enabled channels on the gate. + * ``chan_gate_disable``: Write channel number to disable gate for that + channel. + * ``chan_inuse``: Show the current channels attached to any signal + * ``chan_free``: Show channels with no attached signals. + * ``chan_xtrig_view``: write a channel number to select a channel to view, + read to show the cross triggers programmed for the selected channel. + * ``trig_filter_enable``: Defaults to enabled, disable to allow potentially + dangerous output signals to be set. + * ``trigout_filtered``: Trigger out signals that are prevented from being + set if filtering ``trig_filter_enable`` is enabled. One use is to prevent + accidental ``EDBGREQ`` signals stopping a core. + * ``chan_xtrigs_reset``: Write 1 to clear all channel / trigger programming. + Resets device hardware to default state. + +e.g.:: + + .../cti_sys0/channels# echo 2 1 > trigin_attach + .../cti_sys0/channels# echo 2 6 > trigout_attach + .../cti_sys0/channels# cat chan_free + 0-1,3 + .../cti_sys0/channels# cat chan_inuse + 2 + .../cti_sys0/channels# echo 2 > chan_xtrigs_view + .../cti_sys0/channels# cat chan_xtrigs_view + [2] IN: 1 OUT: 6 + .../cti_sys0/# echo 1 > enable + .../cti_sys0/channels# echo 2 > chan_set + .../cti_sys0/channels# cat ../regs/choutstatus + 0x4 + .../cti_sys0/channels# cat ../regs/trigoutstatus + 0x40 + .../cti_sys0/channels# echo 2 > chan_clear + .../cti_sys0/channels# cat ../regs/trigoutstatus + 0x0 + .../cti_sys0/channels# cat ../regs/trigoutstatus + 0x0 diff --git a/Documentation/trace/coresight/coresight.rst b/Documentation/trace/coresight/coresight.rst index a566719f8e7e..108600ee1e12 100644 --- a/Documentation/trace/coresight/coresight.rst +++ b/Documentation/trace/coresight/coresight.rst @@ -491,8 +491,21 @@ interface provided for that purpose by the generic STM API::
Details on how to use the generic STM API can be found here:- :doc:`../stm` [#second]_.
+The CTI & CTM Modules +--------------------- + +The CTI (Cross Trigger Interface) provides a set of trigger signals between +individual CTIs and components, and can propagate these between all CTIs via +channels on the CTM (Cross Trigger Matrix). + +A separate documentation file is provided to explain the use of these devices. +(:doc:`coresight-ect`) [#fourth]_. + + .. [#first] Documentation/ABI/testing/sysfs-bus-coresight-devices-stm
.. [#second] Documentation/trace/stm.rst
.. [#third] https://github.com/Linaro/perf-opencsd + +.. [#fourth] Documentation/trace/coresight/coresight-ect.rst
On Tue, Nov 19, 2019 at 11:19:11PM +0000, Mike Leach wrote:
Add new document covering CTI / CTM usage in CoreSight.
Add section in coresight.rst introducing CTI and CTM modules with link to new document.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../trace/coresight/coresight-ect.rst | 200 ++++++++++++++++++ Documentation/trace/coresight/coresight.rst | 13 ++ 2 files changed, 213 insertions(+) create mode 100644 Documentation/trace/coresight/coresight-ect.rst
diff --git a/Documentation/trace/coresight/coresight-ect.rst b/Documentation/trace/coresight/coresight-ect.rst new file mode 100644 index 000000000000..6448cf910f20 --- /dev/null +++ b/Documentation/trace/coresight/coresight-ect.rst @@ -0,0 +1,200 @@ +============================================= +CoreSight Embedded Cross Trigger (CTI & CTM). +=============================================
- :Author: Mike Leach mike.leach@linaro.org
- :Date: November 2019
+Hardware Description +--------------------
+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
s/activiating/activating
+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.
+Sysfs files and directories +---------------------------
+The CTI devices appear on the existing CoreSight bus alongside the other +CoreSight devices::
$ ls /sys/bus/coresight/devicescti_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 ctmid enable nr_trigger_cons 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.
- ``nr_trigger_cons`` : total connections - triggers<N> directories.
+*Sub-directories:-*
- ``triggers<N>``: contains list of triggers for an individual connection.
- ``channels``: Contains the channel API - CTI main programming interface.
- ``regs``: Gives access to the raw programmable CTI regs.
- ``mgmt``: the standard CoreSight management registers.
+triggers<N> directories +~~~~~~~~~~~~~~~~~~~~~~~
+Individual trigger connection information. This describes trigger signals for +CoreSight and non-CoreSight 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 Directory +~~~~~~~~~~~~~~~~~~~~~~
+This provides an easy way to attach triggers to channels, without needing +the multiple register operations that are required if manipluating the
s/manipluating/manipulating
+'regs' sub-dir elements directly.
+A number of files provide this API::
$ ls ./cti_sys0/channels/- chan_clear chan_inuse chan_xtrigs_view trigin_detach
- chan_free chan_pulse chan_xtrigs_view_sel trigout_attach
- chan_gate_disable chan_set trig_filter_enable trigout_detach
- chan_gate_enable chan_xtrigs_reset trigin_attach trigout_filtered
+Most access to these elements take the form::
- echo <chan> [<trigger>] > /<device_path>/<operation>
+where the optional <trigger> is only needed for trigXX_attach | detach +operations.
+e.g.::
$ echo 0 1 > ./cti_sys0/channels/trigout_attach $ echo 0 > ./cti_sys0/channels/chan_set+Attaches trigout(1) to channel(0), then activates channel(0) generating a +set state on cti_sys0.trigout(1)
+*API operations*
- ``trigin_attach, trigout_attach``: Attach a channel to a trigger signal.
- ``trigin_detach, trigout_detach``: Detach a channel from a trigger signal.
- ``chan_set``: Set the channel - the set state will be propogated around
s/propogated/propagated
This patch will be handled by Jonathan Corbet and as such he needs to be CC'ed in your next submission