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@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; }