Hi,
-----Original Message----- From: Amir Ayupov aaupov@fb.com Sent: Tuesday, October 13, 2026 12:05 AM To: James Clark james.clark@linaro.org; Leo Yan Leo.Yan@arm.com; Suzuki Poulose Suzuki.Poulose@arm.com; Mike Leach Mike.Leach@arm.com; Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Jonathan Corbet corbet@lwn.net; Randy Dunlap rdunlap@infradead.org; Shuah Khan skhan@linuxfoundation.org; coresight@lists.linaro.org; linux-arm-kernel@lists.infradead.org; linux- doc@vger.kernel.org; linux-kernel@vger.kernel.org Subject: [PATCH v2 3/4] coresight: etm4x: Report the external outputs the PMU counts
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.
The ability of the PMU to count extout events is a feature of the PMU, not a feature of the ETM/ETE.
The capability to use extout in a configuration should be predicated solely on the correctly interpreted values of TRCIDR0 and TRCIDR4 - the number of available extout events.
There does not have to be a valid pmu counter for a configuration using extout to work correctly - indeed the extout connections are often implementation defined and sometimes connected via coresight CTI.
If we have a use case that requires extout to trigger PMUs, then clearly we have both trace software and PMU software that must be initialised and run. It seems more relevant to me that the PMU software should check that it can count the extout when it is run, especially given the PMU command line detailed in the next patch is in part " -e armv8_pmuv3_0/trcextout1,aux-action=pause,period=1000," - specifically identifying extout1 as a parameter
Assisted-by: Devmate:Opus-5.5 Signed-off-by: Amir Ayupov aaupov@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
*/
Not necessarily - this value depends on the ETM version.
- 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);- }
- 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;
PMU connection to extout a feature of PMU not the etm. We don't want to add every single extout connection use-case into the ETM driver. Wouldn't scale well.
Regards
Mike.
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;
}
2.52.0