On 26/10/2026 05:48, 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, whether the PMU counts every external output: the trace unit has an external output for each of its events (caps.nr_event), and pmuv3_event_implemented() reports whether the PMU implements TRCEXTOUTn. Only check ETE: per its specification, an implemented TRCEXTOUTn event counts external output n, while whether that output is also an external input is IMPLEMENTATION DEFINED.
Add a CS_CFG_MATCH_CAP_TRCEXTOUT capability match flag, set it on those trace units, and show it in the feature's configfs 'matches' attribute. With capabilities matched separately from the device class, a feature that requires it only loads on those trace units.
Assisted-by: Devmate:Opus-5.5 Signed-off-by: Amir Ayupov aaupov@fb.com
.../hwtracing/coresight/coresight-config.h | 2 ++ .../hwtracing/coresight/coresight-etm4x-cfg.c | 6 ++++- .../coresight/coresight-etm4x-core.c | 26 +++++++++++++++++++ drivers/hwtracing/coresight/coresight-etm4x.h | 3 +++ .../coresight/coresight-syscfg-configfs.c | 3 +++ 5 files changed, 39 insertions(+), 1 deletion(-)
diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 220bc54f8e5e1..4cf53230854d0 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -38,6 +38,8 @@
- a device that matches one of its classes and has all of its capabilities.
*/ #define CS_CFG_MATCH_CAP_MASK GENMASK_U32(15, 8) +/* the PMU counts the trace unit's external outputs as TRCEXTOUTn */ +#define CS_CFG_MATCH_CAP_TRCEXTOUT BIT(8) /*
- Limit number of presets in a configuration
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c index 52cb036bb04b9..9e4dc5950c13d 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c @@ -176,9 +176,13 @@ 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;
- if (drvdata->caps.trcextout)
match_flags |= CS_CFG_MATCH_CAP_TRCEXTOUT;
- 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 af017bd8a5477..cb5fbb0279b88 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> @@ -1399,6 +1400,29 @@ static void etm4_fixup_wrong_ccitmin(struct etmv4_caps *caps) } } +/*
- Whether the PMU counts each external output of this trace unit as
- TRCEXTOUTn. The trace unit has an external output for each of its events.
- Only ETE is checked: per its specification, an implemented TRCEXTOUTn event
- counts external output n.
- Must run on the CPU that owns the trace unit.
- */
+static bool etm4_pmu_counts_extout(struct etmv4_drvdata *drvdata) +{
- int n;
- if (!etm4x_is_ete(drvdata) || !drvdata->caps.nr_event)
return false;- for (n = 0; n < drvdata->caps.nr_event; n++) {
if (!pmuv3_event_implemented(ARMV8_PMUV3_PERFCTR_TRCEXTOUT0 + n))return false;- }
- return true;
+}
- static void etm4_init_arch_data(void *info) { u32 etmidr0;
@@ -1562,6 +1586,8 @@ static void etm4_init_arch_data(void *info) /* NUMCNTR, bits[30:28] number of counters available for tracing */ caps->nr_cntr = FIELD_GET(TRCIDR5_NUMCNTR_MASK, etmidr5);
- caps->trcextout = etm4_pmu_counts_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 5417280cdb274..33994ad4b2641 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.h +++ b/drivers/hwtracing/coresight/coresight-etm4x.h @@ -868,6 +868,8 @@ enum etm_impdef_type {
- @lpoverride: If the implementation can support low-power state over.
- @skip_power_up: Indicates if an implementation can skip powering up
the trace unit.
- @trcextout: The trace unit is an ETE whose PMU counts its external
*/ struct etmv4_caps { u8 nr_pe;
outputs as TRCEXTOUTn.@@ -907,6 +909,7 @@ struct etmv4_caps { bool atbtrig : 1; bool lpoverride : 1; bool skip_power_up : 1;
- bool trcextout : 1; };
/** diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c index 2b40e556be872..7b3800138f625 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c @@ -250,6 +250,9 @@ 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 ");
- if (match_flags & CS_CFG_MATCH_CAP_TRCEXTOUT)
used += scnprintf(page + used, PAGE_SIZE - used, "TRCEXTOUT ");- used += scnprintf(page + used, PAGE_SIZE - used, "\n"); return used; }
Reviewed-by: James Clark james.clark@linaro.org