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)
Please could we rename this to :
CS_CFG_MATCH_CAP_ETE_TRCEXTOUT
as this is only applicable for ETEs ?
/*
- 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
outputs as TRCEXTOUTn.
We don't seem to be using this after the CSFG flag initialisation, in which case could we directly call etm4_pmu_counts_extout() from etm4_cscfg_register() ?
Suzuki
*/ struct etmv4_caps { u8 nr_pe; @@ -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; }