On 26/10/2026 05:48, Amir Ayupov wrote:
> CS_CFG_MATCH_INST_ANY has been defined since the system configuration was
> introduced but is not used by any configuration, feature or device.
> Remove it.
>
> Suggested-by: Leo Yan <leo.yan(a)arm.com>
> Assisted-by: Devmate:Opus-5.5
> Signed-off-by: Amir Ayupov <aaupov(a)fb.com>
> ---
> drivers/hwtracing/coresight/coresight-config.h | 3 ---
> 1 file changed, 3 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h
> index f04e73b91d9a6..220bc54f8e5e1 100644
> --- a/drivers/hwtracing/coresight/coresight-config.h
> +++ b/drivers/hwtracing/coresight/coresight-config.h
> @@ -39,9 +39,6 @@
> */
> #define CS_CFG_MATCH_CAP_MASK GENMASK_U32(15, 8)
>
> -/* flags defining device instance matching - used in config match desc data. */
> -#define CS_CFG_MATCH_INST_ANY 0x80000000 /* any instance of a class */
> -
> /*
> * Limit number of presets in a configuration
> * This is related to the number of bits (4) we use to select the preset on
Reviewed-by: James Clark <james.clark(a)linaro.org>
On 26/10/2026 05:48, Amir Ayupov wrote:
> A feature loads on a device when the two share any match flag. That works
> for device classes, where a feature wants any one of them, but not for
> capabilities a device may or may not have: a feature that sets a class
> and a capability would still load on a device of that class without the
> capability.
>
> Split the match flags into CS_CFG_MATCH_CLASS_MASK for device classes and
> CS_CFG_MATCH_CAP_MASK for capabilities. A feature now loads on a device
> that shares one of its classes and has all of its capabilities. Check
> this once in cscfg_load_feat_csdev(), which both the feature and the
> device registration paths call. No capability flags are defined yet, so
> matching is unchanged.
>
> Assisted-by: Devmate:Opus-5.5
> Signed-off-by: Amir Ayupov <aaupov(a)fb.com>
> ---
> .../hwtracing/coresight/coresight-config.h | 8 ++++
> .../hwtracing/coresight/coresight-syscfg.c | 37 +++++++++++++------
> 2 files changed, 34 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h
> index ae6295e308131..f04e73b91d9a6 100644
> --- a/drivers/hwtracing/coresight/coresight-config.h
> +++ b/drivers/hwtracing/coresight/coresight-config.h
> @@ -7,6 +7,7 @@
> #ifndef _CORESIGHT_CORESIGHT_CONFIG_H
> #define _CORESIGHT_CORESIGHT_CONFIG_H
>
> +#include <linux/bits.h>
> #include <linux/cleanup.h>
> #include <linux/coresight.h>
> #include <linux/types.h>
> @@ -30,6 +31,13 @@
> */
> #define CS_CFG_MATCH_CLASS_SRC_ALL 0x0001 /* match any source */
> #define CS_CFG_MATCH_CLASS_SRC_ETM4 0x0002 /* match any ETMv4 device */
> +#define CS_CFG_MATCH_CLASS_MASK GENMASK_U32(7, 0)
> +
> +/*
> + * flags defining device capabilities a feature can require. A feature loads on
> + * a device that matches one of its classes and has all of its capabilities.
> + */
> +#define CS_CFG_MATCH_CAP_MASK GENMASK_U32(15, 8)
>
> /* flags defining device instance matching - used in config match desc data. */
> #define CS_CFG_MATCH_INST_ANY 0x80000000 /* any instance of a class */
> diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c
> index a816c22c87bc8..3ee104e94a4cd 100644
> --- a/drivers/hwtracing/coresight/coresight-syscfg.c
> +++ b/drivers/hwtracing/coresight/coresight-syscfg.c
> @@ -171,8 +171,22 @@ cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc
> return feat_csdev;
> }
>
> -/* load one feature into one coresight device */
> +static bool cscfg_match_feat_csdev(u32 feat_flags, u32 csdev_flags)
> +{
> + /* The device must be in one of the feature's classes */
> + if (!(feat_flags & csdev_flags & CS_CFG_MATCH_CLASS_MASK))
> + return false;
> +
> + /* The device must have every capability the feature requires */
> + if (feat_flags & ~csdev_flags & CS_CFG_MATCH_CAP_MASK)
> + return false;
> +
> + return true;
> +}
> +
> +/* Load the feature into the device if it matches, otherwise skip it. */
> static int cscfg_load_feat_csdev(struct coresight_device *csdev,
> + u32 match_flags,
> struct cscfg_feature_desc *feat_desc,
> struct cscfg_csdev_feat_ops *ops)
> {
> @@ -183,6 +197,9 @@ static int cscfg_load_feat_csdev(struct coresight_device *csdev,
> if (!ops->load_feat)
> return -EINVAL;
>
> + if (!cscfg_match_feat_csdev(feat_desc->match_flags, match_flags))
> + return 0;
> +
> feat_csdev = cscfg_alloc_csdev_feat(csdev, feat_desc);
> if (!feat_csdev)
> return -ENOMEM;
> @@ -212,11 +229,11 @@ static int cscfg_add_feat_to_csdevs(struct cscfg_feature_desc *feat_desc)
> int err;
>
> list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
> - if (csdev_item->match_flags & feat_desc->match_flags) {
> - err = cscfg_load_feat_csdev(csdev_item->csdev, feat_desc, &csdev_item->ops);
> - if (err)
> - return err;
> - }
> + err = cscfg_load_feat_csdev(csdev_item->csdev,
> + csdev_item->match_flags, feat_desc,
> + &csdev_item->ops);
> + if (err)
> + return err;
> }
> return 0;
> }
> @@ -739,11 +756,9 @@ static int cscfg_add_feats_csdev(struct coresight_device *csdev,
> return -EINVAL;
>
> list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
> - if (feat_desc->match_flags & match_flags) {
> - err = cscfg_load_feat_csdev(csdev, feat_desc, ops);
> - if (err)
> - break;
> - }
> + err = cscfg_load_feat_csdev(csdev, match_flags, feat_desc, ops);
> + if (err)
> + break;
> }
> return err;
> }
Reviewed-by: James Clark <james.clark(a)linaro.org>
On 26/10/2026 05:48, Amir Ayupov wrote:
> From: Leo Yan <leo.yan(a)arm.com>
>
> TRCIDR0.NUMEVENT normally encodes the number of events minus one.
> From ETMv4.3 onwards, including ETE, a zero TRCIDR4.NUMRSPAIR instead
> means that no events are implemented and NUMEVENT is zero. The sysfs
> event controls currently interpret this combination as one event and
> allow writes to unsupported event fields.
>
> Decode NUMEVENT after NUMRSPAIR and store the actual number of events
> in nr_event. Use the decoded resource count so that older ETM versions,
> where a zero NUMRSPAIR represents one resource pair, still report at
> least one event. Update both sysfs event controls to use the actual
> count and clear their event fields when no events are implemented.
>
> Also correct the instruction event enable mask for the single-event
> case to use INSTEN[0]. The existing mask uses INSTEN[1], preventing
> event 0 from being enabled.
>
> This change depends on the recent driver refactoring. With no reported
> failures, it is not intended for stable backporting.
>
> Signed-off-by: Leo Yan <leo.yan(a)arm.com>
> ---
> .../coresight/coresight-etm4x-core.c | 13 +++++++--
> .../coresight/coresight-etm4x-sysfs.c | 29 ++++++++++---------
> 2 files changed, 27 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> index e21be6468e954..af017bd8a5477 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> @@ -1451,8 +1451,6 @@ static void etm4_init_arch_data(void *info)
> caps->trccci = !!(etmidr0 & TRCIDR0_TRCCCI);
> /* RETSTACK, bit[9] Return stack bit */
> caps->retstack = !!(etmidr0 & TRCIDR0_RETSTACK);
> - /* NUMEVENT, bits[11:10] Number of events field */
> - caps->nr_event = FIELD_GET(TRCIDR0_NUMEVENT_MASK, etmidr0);
> /* QSUPP, bits[16:15] Q element support field */
> caps->q_support = FIELD_GET(TRCIDR0_QSUPP_MASK, etmidr0);
> if (caps->q_support)
> @@ -1519,6 +1517,17 @@ static void etm4_init_arch_data(void *info)
> caps->nr_resource = FIELD_GET(TRCIDR4_NUMRSPAIR_MASK, etmidr4);
> if ((drvdata->arch < ETM_ARCH_V4_3) || (caps->nr_resource > 0))
> caps->nr_resource += 1;
> +
> + /*
> + * NUMEVENT encodes the number of events minus one. From ETMv4.3,
> + * including ETE, NUMRSPAIR == 0 means no events are implemented.
> + * nr_resource already accounts for the pre-ETMv4.3 encoding.
> + */
> + if (caps->nr_resource)
> + caps->nr_event = FIELD_GET(TRCIDR0_NUMEVENT_MASK, etmidr0) + 1;
> + else
> + caps->nr_event = 0;
> +
> /*
> * NUMSSCC, bits[23:20] the number of single-shot
> * comparator control for tracing. Read any status regs as these
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> index db9e603f97ba8..fb38f0102290a 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> @@ -513,19 +513,22 @@ static ssize_t event_store(struct device *dev,
>
> raw_spin_lock(&drvdata->spinlock);
> switch (caps->nr_event) {
> - case 0x0:
> + case 0:
> + sysfs_config->eventctrl0 = 0;
> + break;
> + case 1:
> /* EVENT0, bits[7:0] */
> sysfs_config->eventctrl0 = val & 0xFF;
> break;
> - case 0x1:
> - /* EVENT1, bits[15:8] */
> + case 2:
> + /* EVENT1, bits[15:8] */
> sysfs_config->eventctrl0 = val & 0xFFFF;
> break;
> - case 0x2:
> + case 3:
> /* EVENT2, bits[23:16] */
> sysfs_config->eventctrl0 = val & 0xFFFFFF;
> break;
> - case 0x3:
> + case 4:
> /* EVENT3, bits[31:24] */
> sysfs_config->eventctrl0 = val;
> break;
> @@ -565,22 +568,22 @@ static ssize_t event_instren_store(struct device *dev,
> /* start by clearing all instruction event enable bits */
> sysfs_config->eventctrl1 &= ~TRCEVENTCTL1R_INSTEN_MASK;
> switch (caps->nr_event) {
> - case 0x0:
> - /* generate Event element for event 1 */
> - sysfs_config->eventctrl1 |= val & TRCEVENTCTL1R_INSTEN_1;
> + case 1:
> + /* generate Event element for event 0 */
> + sysfs_config->eventctrl1 |= val & TRCEVENTCTL1R_INSTEN_0;
> break;
> - case 0x1:
> - /* generate Event element for event 1 and 2 */
> + case 2:
> + /* generate Event element for events 0 and 1 */
> sysfs_config->eventctrl1 |= val & (TRCEVENTCTL1R_INSTEN_0 |
> TRCEVENTCTL1R_INSTEN_1);
> break;
> - case 0x2:
> - /* generate Event element for event 1, 2 and 3 */
> + case 3:
> + /* generate Event element for events 0, 1 and 2 */
> sysfs_config->eventctrl1 |= val & (TRCEVENTCTL1R_INSTEN_0 |
> TRCEVENTCTL1R_INSTEN_1 |
> TRCEVENTCTL1R_INSTEN_2);
> break;
> - case 0x3:
> + case 4:
> /* generate Event element for all 4 events */
> sysfs_config->eventctrl1 |= val & (TRCEVENTCTL1R_INSTEN_0 |
> TRCEVENTCTL1R_INSTEN_1 |
Reviewed-by: James Clark <james.clark(a)linaro.org>
On 25/10/2026 06:38, Amir Ayupov wrote:
> On Mon, 12 Oct 2026 22:09:35 -0300 Daniel Pereira <danielmaraboo(a)gmail.com> wrote:
>
>> On Mon, Oct 12, 2026 at 04:05:23PM -0700, Amir Ayupov wrote:
>> [...]
>>> + perf record -T \
>>> + -e cs_etm/pmu_pulse,aux-action=start-paused,timestamp/u \
>>> + -e armv8_pmuv3_0/cpu_cycles,aux-action=resume,period=1050031/u \
>>> + -e armv8_pmuv3_0/trcextout1,aux-action=pause,period=1000,call-graph=fp/u \
>>> + -- ./workload
>>
>> The CPU PMU name depends on the system: armv8_pmuv3_0 is what ACPI
>> systems get, while on devicetree systems it comes from the compatible
>> string, e.g. armv8_pmuv3 or armv8_cortex_a76. Maybe add a sentence
>> after the example, along the lines of:
>>
>> The CPU PMU name depends on the system; the available PMUs are
>> listed under /sys/bus/event_source/devices/.
> I'd rather drop PMU specifiers as this is not something this patch
> series focuses on, and examples above avoid them too.
I agree. Making the docs overly verbose makes them less useful. And I
can't see a use case where a user would get stuck converting this
example to their own system.
>>
>> I applied the documentation hunks and built htmldocs, no new warnings.
>> With or without the above, for the documentation part:
>>
>> Reviewed-by: Daniel Pereira <danielmaraboo(a)gmail.com>
>>
>> Thanks,
>> Daniel
>
> Sent using hkml (https://github.com/sjp38/hackermail)
On Mon, Oct 12, 2026 at 04:05:22PM -0700, Amir Ayupov wrote:
[...]
> --- a/drivers/hwtracing/coresight/coresight-config.h
> +++ b/drivers/hwtracing/coresight/coresight-config.h
> @@ -35,6 +35,10 @@
> * a device that matches one of its classes and has all of its capabilities.
> */
> #define CS_CFG_MATCH_CAP_MASK 0x0000ff00
> +/* trace unit external output n is countable by the PMU as TRCEXTOUTn */
> +#define CS_CFG_MATCH_CAP_PMU_EXTOUT_SHIFT 8
> +#define CS_CFG_MATCH_CAP_PMU_EXTOUT_NR 4 /* TRCEXTOUT0-3 */
> +#define CS_CFG_MATCH_CAP_PMU_EXTOUT(n) BIT(CS_CFG_MATCH_CAP_PMU_EXTOUT_SHIFT + (n))
We can just use a single capacity for all output singals. It would be
good to follow the naming convention in the Arm ARM:
#define CS_CFG_MATCH_CAP_TRCEXTOUT BIT(8)
> int etm4_cscfg_register(struct coresight_device *csdev)
> {
> + struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
> struct cscfg_csdev_feat_ops ops;
> + u32 match_flags = CS_CFG_ETM4_MATCH_FLAGS;
>
> ops.load_feat = &etm4_cfg_load_feature;
> + match_flags |= (u32)drvdata->pmu_extout << CS_CFG_MATCH_CAP_PMU_EXTOUT_SHIFT;
>
> - return cscfg_register_csdev(csdev, CS_CFG_ETM4_MATCH_FLAGS, &ops);
> + return cscfg_register_csdev(csdev, match_flags, &ops);
I would suggest to enable the capability bit base on drvdata->caps:
if (etm4x_is_ete(drvdata) && drvdata->caps.nr_events)
match_flags |= CS_CFG_MATCH_CAP_TRCEXTOUT;
For now, we can enable TRCEXTOUT for ETE only, as this should be
sufficient to detect the feature safely. I'd like to leave this to
James and Mike as I got suggestions from them.
Please also rebase onto the latest CoreSight next branch [1], which
moves the capability fields into drvdata->caps. I found an issue in the
decoding of caps.nr_event; the attached patch fixes it and makes the
field hold the actual event count.
[1] https://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux.git branch: next
---8<---
From 95307fa0574b1e0b3922ffa23fe98144b2688496 Mon Sep 17 00:00:00 2001
From: Leo Yan <leo.yan(a)arm.com>
Date: Wed, 21 Oct 2026 17:05:18 +0100
Subject: [PATCH] coresight: etm4x: Fix event count decoding
TRCIDR0.NUMEVENT normally encodes the number of events minus one.
From ETMv4.3 onwards, including ETE, a zero TRCIDR4.NUMRSPAIR instead
means that no events are implemented and NUMEVENT is zero. The sysfs
event controls currently interpret this combination as one event and
allow writes to unsupported event fields.
Decode NUMEVENT after NUMRSPAIR and store the actual number of events
in nr_event. Use the decoded resource count so that older ETM versions,
where a zero NUMRSPAIR represents one resource pair, still report at
least one event. Update both sysfs event controls to use the actual
count and clear their event fields when no events are implemented.
Also correct the instruction event enable mask for the single-event
case to use INSTEN[0]. The existing mask uses INSTEN[1], preventing
event 0 from being enabled.
This change depends on the recent driver refactoring. With no reported
failures, it is not intended for stable backporting.
Signed-off-by: Leo Yan <leo.yan(a)arm.com>
---
.../coresight/coresight-etm4x-core.c | 13 +++++++--
.../coresight/coresight-etm4x-sysfs.c | 29 ++++++++++---------
2 files changed, 27 insertions(+), 15 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index e21be6468e954..af017bd8a5477 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -1451,8 +1451,6 @@ static void etm4_init_arch_data(void *info)
caps->trccci = !!(etmidr0 & TRCIDR0_TRCCCI);
/* RETSTACK, bit[9] Return stack bit */
caps->retstack = !!(etmidr0 & TRCIDR0_RETSTACK);
- /* NUMEVENT, bits[11:10] Number of events field */
- caps->nr_event = FIELD_GET(TRCIDR0_NUMEVENT_MASK, etmidr0);
/* QSUPP, bits[16:15] Q element support field */
caps->q_support = FIELD_GET(TRCIDR0_QSUPP_MASK, etmidr0);
if (caps->q_support)
@@ -1519,6 +1517,17 @@ static void etm4_init_arch_data(void *info)
caps->nr_resource = FIELD_GET(TRCIDR4_NUMRSPAIR_MASK, etmidr4);
if ((drvdata->arch < ETM_ARCH_V4_3) || (caps->nr_resource > 0))
caps->nr_resource += 1;
+
+ /*
+ * NUMEVENT encodes the number of events minus one. From ETMv4.3,
+ * including ETE, NUMRSPAIR == 0 means no events are implemented.
+ * nr_resource already accounts for the pre-ETMv4.3 encoding.
+ */
+ if (caps->nr_resource)
+ caps->nr_event = FIELD_GET(TRCIDR0_NUMEVENT_MASK, etmidr0) + 1;
+ else
+ caps->nr_event = 0;
+
/*
* NUMSSCC, bits[23:20] the number of single-shot
* comparator control for tracing. Read any status regs as these
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
index db9e603f97ba8..fb38f0102290a 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
@@ -513,19 +513,22 @@ static ssize_t event_store(struct device *dev,
raw_spin_lock(&drvdata->spinlock);
switch (caps->nr_event) {
- case 0x0:
+ case 0:
+ sysfs_config->eventctrl0 = 0;
+ break;
+ case 1:
/* EVENT0, bits[7:0] */
sysfs_config->eventctrl0 = val & 0xFF;
break;
- case 0x1:
- /* EVENT1, bits[15:8] */
+ case 2:
+ /* EVENT1, bits[15:8] */
sysfs_config->eventctrl0 = val & 0xFFFF;
break;
- case 0x2:
+ case 3:
/* EVENT2, bits[23:16] */
sysfs_config->eventctrl0 = val & 0xFFFFFF;
break;
- case 0x3:
+ case 4:
/* EVENT3, bits[31:24] */
sysfs_config->eventctrl0 = val;
break;
@@ -565,22 +568,22 @@ static ssize_t event_instren_store(struct device *dev,
/* start by clearing all instruction event enable bits */
sysfs_config->eventctrl1 &= ~TRCEVENTCTL1R_INSTEN_MASK;
switch (caps->nr_event) {
- case 0x0:
- /* generate Event element for event 1 */
- sysfs_config->eventctrl1 |= val & TRCEVENTCTL1R_INSTEN_1;
+ case 1:
+ /* generate Event element for event 0 */
+ sysfs_config->eventctrl1 |= val & TRCEVENTCTL1R_INSTEN_0;
break;
- case 0x1:
- /* generate Event element for event 1 and 2 */
+ case 2:
+ /* generate Event element for events 0 and 1 */
sysfs_config->eventctrl1 |= val & (TRCEVENTCTL1R_INSTEN_0 |
TRCEVENTCTL1R_INSTEN_1);
break;
- case 0x2:
- /* generate Event element for event 1, 2 and 3 */
+ case 3:
+ /* generate Event element for events 0, 1 and 2 */
sysfs_config->eventctrl1 |= val & (TRCEVENTCTL1R_INSTEN_0 |
TRCEVENTCTL1R_INSTEN_1 |
TRCEVENTCTL1R_INSTEN_2);
break;
- case 0x3:
+ case 4:
/* generate Event element for all 4 events */
sysfs_config->eventctrl1 |= val & (TRCEVENTCTL1R_INSTEN_0 |
TRCEVENTCTL1R_INSTEN_1 |
--
2.34.1
On Wed, Oct 21, 2026 at 10:03:22AM +0800, Johnny.Fan wrote:
> These synthetic devices have no fwnode, so the firmware-described
> IRQ affinity cannot tell which CPUs implement the feature. Pass the
> CPU mask as platform data and have the drivers prefer it over the
> IRQ affinity when present.
Could the MADT-derived CPU masks be exposed through
platform_get_irq_affinity(), so SPE and TRBE can continue using the
common interface without fetching ACPI-specific data?
TBC, I don't know ACPI or GIC. I just thought it might be a neat
approach.
> Apply the same treatment to TRBE, which shares this registration
> code. TRBE must also pass a stable copy of the mask to
> request_percpu_irq_affinity(), since supported_cpus is pruned as
> CPUs are probed.
I wouldn't expect any changes to the SPE or TRBE drivers if
platform_get_irq_affinity() can return the correct CPU mask.
Thanks,
Leo
On 13/10/2026 00:05, Amir Ayupov wrote:
> Some CPUs count the trace unit's external outputs as the PMU common
> events TRCEXTOUT0-3 (0x4010-0x4013), which lets a configuration drive a
> PMU event from trace unit events. Other CPUs, Neoverse N1 for example,
> have no such events, and a feature relying on them would silently do
> nothing there.
>
> Detect at probe, on the trace unit's CPU, which outputs the PMU counts:
> the trace unit has an external output for each of its events
> (TRCIDR0.NUMEVENT), and from PMUv3p1, PMCEID0_EL0[63:32] reports which of
> the common events 0x4000-0x401f are implemented. Per the ETE
> specification, an implemented TRCEXTOUTn event counts external output n;
> only whether that output is also an external input is IMPLEMENTATION
> DEFINED.
>
> Add a capability match flag for each output,
> CS_CFG_MATCH_CAP_PMU_EXTOUT(n), set it on ETMs whose PMU counts that
> output, and show it in the feature's configfs 'matches' attribute. With
> capabilities matched separately from the device class, a feature that
> requires one only loads on those ETMs.
>
> Assisted-by: Devmate:Opus-5.5
> Signed-off-by: Amir Ayupov <aaupov(a)fb.com>
> ---
> .../hwtracing/coresight/coresight-config.h | 4 +++
> .../hwtracing/coresight/coresight-etm4x-cfg.c | 5 ++-
> .../coresight/coresight-etm4x-core.c | 32 +++++++++++++++++++
> drivers/hwtracing/coresight/coresight-etm4x.h | 3 ++
> .../coresight/coresight-syscfg-configfs.c | 7 ++++
> 5 files changed, 50 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h
> index af6ef96b9ae01..10e95f5ecc8d9 100644
> --- a/drivers/hwtracing/coresight/coresight-config.h
> +++ b/drivers/hwtracing/coresight/coresight-config.h
> @@ -35,6 +35,10 @@
> * a device that matches one of its classes and has all of its capabilities.
> */
> #define CS_CFG_MATCH_CAP_MASK 0x0000ff00
> +/* trace unit external output n is countable by the PMU as TRCEXTOUTn */
> +#define CS_CFG_MATCH_CAP_PMU_EXTOUT_SHIFT 8
> +#define CS_CFG_MATCH_CAP_PMU_EXTOUT_NR 4 /* TRCEXTOUT0-3 */
> +#define CS_CFG_MATCH_CAP_PMU_EXTOUT(n) BIT(CS_CFG_MATCH_CAP_PMU_EXTOUT_SHIFT + (n))
>
> /* flags defining device instance matching - used in config match desc data. */
> #define CS_CFG_MATCH_INST_ANY 0x80000000 /* any instance of a class */
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> index e1a59b4345052..09a7a6b86968c 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> @@ -174,9 +174,12 @@ static int etm4_cfg_load_feature(struct coresight_device *csdev,
>
> int etm4_cscfg_register(struct coresight_device *csdev)
> {
> + struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
> struct cscfg_csdev_feat_ops ops;
> + u32 match_flags = CS_CFG_ETM4_MATCH_FLAGS;
>
> ops.load_feat = &etm4_cfg_load_feature;
> + match_flags |= (u32)drvdata->pmu_extout << CS_CFG_MATCH_CAP_PMU_EXTOUT_SHIFT;
>
> - return cscfg_register_csdev(csdev, CS_CFG_ETM4_MATCH_FLAGS, &ops);
> + return cscfg_register_csdev(csdev, match_flags, &ops);
> }
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> index 2247ad55d4442..1e78774025d13 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> @@ -30,6 +30,7 @@
> #include <linux/uaccess.h>
> #include <linux/perf_event.h>
> #include <linux/perf/arm_pmu.h>
> +#include <linux/perf/arm_pmuv3.h>
> #include <linux/platform_device.h>
> #include <linux/pm_runtime.h>
> #include <linux/property.h>
> @@ -1368,6 +1369,35 @@ static void etm4_fixup_wrong_ccitmin(struct etmv4_drvdata *drvdata)
> }
> }
>
> +/*
> + * Find the external outputs of this trace unit that the PMU counts as the
> + * common events TRCEXTOUT0-3. The trace unit has an external output for each
> + * of its events, and PMCEID0_EL0[63:32] reports the common events
> + * 0x4000-0x401f from PMUv3p1.
> + *
> + * Must run on the CPU that owns the trace unit.
> + */
> +static u8 etm4_pmu_extout(struct etmv4_drvdata *drvdata)
> +{
> + int pmuver = read_pmuver();
> + u64 pmceid;
> + u8 extout = 0;
> + int n;
> +
> + if (!pmuv3_implemented(pmuver) || pmuver < ID_AA64DFR0_EL1_PMUVer_V3P1)
> + return 0;
> +
> + pmceid = read_pmceid0() >> 32;
> + /* nr_event is TRCIDR0.NUMEVENT, the number of events minus one */
> + for (n = 0; n <= drvdata->nr_event; n++) {
> + if (pmceid & BIT_ULL(ARMV8_PMUV3_PERFCTR_TRCEXTOUT0 + n -
> + ARMV8_PMUV3_EXT_COMMON_EVENT_BASE))
> + extout |= BIT(n);
> + }
Maybe an pmuv3_event_implemented() function in arm_pmuv3.c would be a
better fit for this. It can do something like:
if (event > ARMV8_PMUV3_EXT_COMMON_EVENT_BASE)
return (event - ARMV8_PMUV3_EXT_COMMON_EVENT_BASE) & pmceid_IDhi;
else
return event & pmceid_IDlo;
etc.
> +
> + return extout;
> +}
> +
> static void etm4_init_arch_data(void *info)
> {
> u32 etmidr0;
> @@ -1522,6 +1552,8 @@ static void etm4_init_arch_data(void *info)
> /* NUMCNTR, bits[30:28] number of counters available for tracing */
> drvdata->nr_cntr = FIELD_GET(TRCIDR5_NUMCNTR_MASK, etmidr5);
>
> + drvdata->pmu_extout = etm4_pmu_extout(drvdata);
> +
> coresight_clear_self_claim_tag_unlocked(csa);
> etm4_cs_lock(drvdata, csa);
> cpu_detect_trace_filtering(drvdata);
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
> index df9e0748d71ec..11d95a4518b88 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x.h
> +++ b/drivers/hwtracing/coresight/coresight-etm4x.h
> @@ -979,6 +979,8 @@ struct etmv4_save_state {
> * @nrseqstate: The number of sequencer states that are implemented.
> * @nr_seq_ctrls: The number of sequence state transition control registers.
> * @nr_event: Indicates how many events the trace unit support.
> + * @pmu_extout: Bitmap of the external outputs n that the PMU counts as
> + * TRCEXTOUTn.
> * @nr_resource:The number of resource selection pairs available for tracing.
> * @nr_ss_cmp: Number of single-shot comparator controls that are available.
> * @trcid: value of the current ID for this component.
> @@ -1045,6 +1047,7 @@ struct etmv4_drvdata {
> u8 nrseqstate;
> u8 nr_seq_ctrls;
> u8 nr_event;
> + u8 pmu_extout;
> u8 nr_resource;
> u8 nr_ss_cmp;
> u8 trcid;
> diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c
> index 2b40e556be872..7893d40f2e9ea 100644
> --- a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c
> +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c
> @@ -243,6 +243,7 @@ static ssize_t cscfg_feat_matches_show(struct config_item *item, char *page)
> struct cscfg_fs_feature, group);
> u32 match_flags = fs_feat->feat_desc->match_flags;
> int used = 0;
> + int n;
>
> if (match_flags & CS_CFG_MATCH_CLASS_SRC_ALL)
> used = scnprintf(page, PAGE_SIZE, "SRC_ALL ");
> @@ -250,6 +251,12 @@ static ssize_t cscfg_feat_matches_show(struct config_item *item, char *page)
> if (match_flags & CS_CFG_MATCH_CLASS_SRC_ETM4)
> used += scnprintf(page + used, PAGE_SIZE - used, "SRC_ETMV4 ");
>
> + for (n = 0; n < CS_CFG_MATCH_CAP_PMU_EXTOUT_NR; n++) {
> + if (match_flags & CS_CFG_MATCH_CAP_PMU_EXTOUT(n))
> + used += scnprintf(page + used, PAGE_SIZE - used,
> + "PMU_EXTOUT%d ", n);
> + }
> +
> used += scnprintf(page + used, PAGE_SIZE - used, "\n");
> return used;
> }
TRCIDR0.NUMEVENT normally encodes the number of events minus one.
From ETMv4.3 onwards, including ETE, a zero TRCIDR4.NUMRSPAIR instead
means that no events are implemented and NUMEVENT is zero. The sysfs
event controls currently interpret this combination as one event and
allow writes to unsupported event fields.
Decode NUMEVENT after NUMRSPAIR and store the actual number of events
in nr_event. Use the decoded resource count so that older ETM versions,
where a zero NUMRSPAIR represents one resource pair, still report at
least one event. Update both sysfs event controls to use the actual
count and clear their event fields when no events are implemented.
Also correct the instruction event enable mask for the single-event
case to use INSTEN[0]. The existing mask uses INSTEN[1], preventing
event 0 from being enabled.
This change depends on the recent driver refactoring. With no reported
failures, it is not intended for stable backporting.
Signed-off-by: Leo Yan <leo.yan(a)arm.com>
---
drivers/hwtracing/coresight/coresight-etm4x-core.c | 15 +++++++++--
.../hwtracing/coresight/coresight-etm4x-sysfs.c | 29 ++++++++++++----------
2 files changed, 29 insertions(+), 15 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index e21be6468e9544fe6e22f524de4fef9f89d7484f..b0e286f487017a4155595f14cbb9c9c33b17dc6b 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -1451,8 +1451,6 @@ static void etm4_init_arch_data(void *info)
caps->trccci = !!(etmidr0 & TRCIDR0_TRCCCI);
/* RETSTACK, bit[9] Return stack bit */
caps->retstack = !!(etmidr0 & TRCIDR0_RETSTACK);
- /* NUMEVENT, bits[11:10] Number of events field */
- caps->nr_event = FIELD_GET(TRCIDR0_NUMEVENT_MASK, etmidr0);
/* QSUPP, bits[16:15] Q element support field */
caps->q_support = FIELD_GET(TRCIDR0_QSUPP_MASK, etmidr0);
if (caps->q_support)
@@ -1519,6 +1517,19 @@ static void etm4_init_arch_data(void *info)
caps->nr_resource = FIELD_GET(TRCIDR4_NUMRSPAIR_MASK, etmidr4);
if ((drvdata->arch < ETM_ARCH_V4_3) || (caps->nr_resource > 0))
caps->nr_resource += 1;
+
+ /*
+ * See ARM IHI0064H.b, sections 7.3.32 (TRCIDR0) and 7.3.36 (TRCIDR4).
+ *
+ * Before ETMv4.3, one event is always implemented. For ETM v4.3 and
+ * later, NUMRSPAIR == 0 indicates that no events are implemented.
+ * Otherwise, NUMEVENT encodes the number of events minus one.
+ */
+ if (caps->nr_resource)
+ caps->nr_event = FIELD_GET(TRCIDR0_NUMEVENT_MASK, etmidr0) + 1;
+ else
+ caps->nr_event = 0;
+
/*
* NUMSSCC, bits[23:20] the number of single-shot
* comparator control for tracing. Read any status regs as these
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
index db9e603f97ba82cd608d3d61881fe8153db020ff..fb38f0102290a53a681934c827abf107c141a740 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
@@ -513,19 +513,22 @@ static ssize_t event_store(struct device *dev,
raw_spin_lock(&drvdata->spinlock);
switch (caps->nr_event) {
- case 0x0:
+ case 0:
+ sysfs_config->eventctrl0 = 0;
+ break;
+ case 1:
/* EVENT0, bits[7:0] */
sysfs_config->eventctrl0 = val & 0xFF;
break;
- case 0x1:
- /* EVENT1, bits[15:8] */
+ case 2:
+ /* EVENT1, bits[15:8] */
sysfs_config->eventctrl0 = val & 0xFFFF;
break;
- case 0x2:
+ case 3:
/* EVENT2, bits[23:16] */
sysfs_config->eventctrl0 = val & 0xFFFFFF;
break;
- case 0x3:
+ case 4:
/* EVENT3, bits[31:24] */
sysfs_config->eventctrl0 = val;
break;
@@ -565,22 +568,22 @@ static ssize_t event_instren_store(struct device *dev,
/* start by clearing all instruction event enable bits */
sysfs_config->eventctrl1 &= ~TRCEVENTCTL1R_INSTEN_MASK;
switch (caps->nr_event) {
- case 0x0:
- /* generate Event element for event 1 */
- sysfs_config->eventctrl1 |= val & TRCEVENTCTL1R_INSTEN_1;
+ case 1:
+ /* generate Event element for event 0 */
+ sysfs_config->eventctrl1 |= val & TRCEVENTCTL1R_INSTEN_0;
break;
- case 0x1:
- /* generate Event element for event 1 and 2 */
+ case 2:
+ /* generate Event element for events 0 and 1 */
sysfs_config->eventctrl1 |= val & (TRCEVENTCTL1R_INSTEN_0 |
TRCEVENTCTL1R_INSTEN_1);
break;
- case 0x2:
- /* generate Event element for event 1, 2 and 3 */
+ case 3:
+ /* generate Event element for events 0, 1 and 2 */
sysfs_config->eventctrl1 |= val & (TRCEVENTCTL1R_INSTEN_0 |
TRCEVENTCTL1R_INSTEN_1 |
TRCEVENTCTL1R_INSTEN_2);
break;
- case 0x3:
+ case 4:
/* generate Event element for all 4 events */
sysfs_config->eventctrl1 |= val & (TRCEVENTCTL1R_INSTEN_0 |
TRCEVENTCTL1R_INSTEN_1 |
---
base-commit: 343cfcbb3ecfdb80aa576a428cfa3b65ad783842
change-id: 20261022-arm_cs_fix_etm4_event_count-49f384a2f6a7
Best regards,
--
Leo Yan <leo.yan(a)arm.com>