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>
The driver might not always be able to write HW_IDs, but we don't need
them for unformatted mode anyway, so fix that in commit ("perf cs-etm:
Synthesize missing HW_ID mappings for raw trace").
Include some other minor improvements encountered on the way to appease
Sashiko, like properly freeing queues and ("perf: cs-etm: Respect
--no-itrace option") makes debugging broken Coresight perf.data files
easier.
Signed-off-by: James Clark <james.clark(a)linaro.org>
---
Changes in v3:
- Remove old b4 prerequisite metadata that's no longer relevant.
- Link to v2: https://patch.msgid.link/20261002-james-cs-hw_id-output-failure-v2-0-7a194a…
Changes in v2:
- Drop driver changes and move to https://lore.kernel.org/linux-perf-users/20261001-james-cs-retry-hw_id-v1-0…
- Don't process any HW_IDs for unformatted queues, just create decoders
unconditionally with trace ID 1.
- Use zfree() instead of etmq->decoder = NULL
- Remove dependency on "[PATCH v2 00/14] perf cs-etm: Per-thread mode
fixes and snapshot wrap support", it wasn't functionally dependant,
just touching some of the same lines.
- Link to v1: https://patch.msgid.link/20260821-james-cs-hw_id-output-failure-v1-0-9d532d…
---
James Clark (3):
perf: cs-etm: Don't add global v0 HW_IDs to unformatted queues
perf cs-etm: Free partially created queues
perf: cs-etm: Respect --no-itrace option
Leo Yan (1):
perf cs-etm: Synthesize missing HW_ID mappings for raw trace
tools/perf/util/auxtrace.c | 2 +-
tools/perf/util/auxtrace.h | 1 +
tools/perf/util/cs-etm-decoder/cs-etm-decoder.c | 12 +-
tools/perf/util/cs-etm-decoder/cs-etm-decoder.h | 2 +-
tools/perf/util/cs-etm.c | 184 +++++++++++++++---------
5 files changed, 123 insertions(+), 78 deletions(-)
---
base-commit: 705da5b15ab89ba97b11eedbe507c2fd83d31cb9
change-id: 20260706-james-cs-hw_id-output-failure-1d06d042ef96
Best regards,
--
James Clark <james.clark(a)linaro.org>
On Mon, Oct 12, 2026 at 04:05:20PM -0700, Amir Ayupov wrote:
> cscfg_csdev_enable_active_config() looks up the selected configuration in
> the device's loaded configurations, and returns success when it is not
> there. A configuration is only loaded on devices that match at least one
> of its features, so a perf session or sysfs enable that selects it on any
> other device runs without the configuration, with no error.
>
> Return -EINVAL instead, so enabling the source fails on that device. The
> function is only called with a non-zero configuration hash, so sources
> enabled without a configuration are unaffected.
>
> Fixes: f8cce2ff3c04 ("coresight: syscfg: Add API to activate and enable configurations")
> Assisted-by: Devmate:Opus-5.5
> Signed-off-by: Amir Ayupov <aaupov(a)fb.com>
Reviewed-by: Leo Yan <leo.yan(a)arm.com>
Fix a few issues with per-thread mode:
- With TRBE, thread migrations hit a queue without a decoder assert
- On nVHE, everything looks like guest trace instead of host
- Tracing multiple threads didn't really work
After adding a tests for those, it turns out there were some snapshot
bugs not picked up by the other snapshot tests. That showed that the
different snapshot searches for Intel BTS and Arm SPE were inconsistent
and I think all tracers can benefit from using the same pointer fixup
logic, so that gets refactored into the common auxtrace.c. Then SPE can
just share the Intel BTS search as it was obviously copied from it
originally. IntelPT keeps the more advanced duplicate data search, but
in the future that could probably be made the common one and all tracers
would benefit from using it (except maybe BTS if it always has a very
small buffer, but I doubt the overhead of the duplicate search would be
an issue). For now this is more of a refactor rather than behavioral
change so don't do that yet.
Signed-off-by: James Clark <james.clark(a)linaro.org>
---
Changes in v2:
- Remove stale "may be reset to -1 in per-thread mode" comment
- Set CPU when queueing auxtrace fragments otherwise
auxtrace_queues__add_event() overwrites the queue's CPU
- Link to v1: https://patch.msgid.link/20260811-james-cs-unformatted-per-thread-fix-v1-0-…
---
James Clark (14):
perf cs-etm: Fix nVHE per-thread decoding
perf cs-etm: Warn for invalid timestamp option
perf cs-etm: Turn on context packet timestamps in per-thread mode
perf cs-etm: Use per-CPU queues for per-thread mode
perf cs-etm: Increase default timestamp generation period
perf auxtrace: Turn Intel BTS snapshot search into a generic one
perf arm-spe: Use generic snapshot search
perf auxtrace: intel-pt: Use new snapshot_has_wrapped callback
perf cs-etm: Queue partial AUX records
perf cs-etm: Don't print missing buffers in snapshot mode
perf auxtrace: cs-etm: Capture wrapped snapshots
perf test: Allow infinite named_thread loops
perf test: Add test for per-thread mode
perf cs-etm: Test multiple per-thread threads
Documentation/userspace-api/perf_ring_buffer.rst | 6 +-
tools/perf/Documentation/perf-test.txt | 2 +-
tools/perf/arch/arm/util/cs-etm.c | 30 ++++-
tools/perf/arch/arm64/util/arm-spe.c | 147 +--------------------
tools/perf/arch/x86/util/intel-bts.c | 115 +---------------
tools/perf/arch/x86/util/intel-pt.c | 58 +++-----
.../perf/tests/shell/coresight/per-thread-multi.sh | 78 +++++++++++
tools/perf/tests/shell/coresight/per-thread.sh | 48 +++++++
.../perf/tests/shell/coresight/raw_dump_stress.sh | 5 -
tools/perf/tests/workloads/named_threads.c | 7 +-
tools/perf/util/auxtrace.c | 136 +++++++++++++++++--
tools/perf/util/auxtrace.h | 20 ++-
tools/perf/util/cs-etm.c | 101 ++++++++++----
13 files changed, 384 insertions(+), 369 deletions(-)
---
base-commit: 9453bc6a69ef43755f1c28d5688cacdd69fa16bd
change-id: 20260605-james-cs-unformatted-per-thread-fix-50e723aa7f0e
Best regards,
--
James Clark <james.clark(a)linaro.org>