Skip to contentSkip to conversation

coresight: Pulse an ETM external output for a PMU event

PATCH Superseded Amir Ayupov 8 participants 63 messages Oct 12 – Nov 10

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

v2 cover coresight: Pulse an ETM external output for a PMU event

Add an ETMv4 configuration, pmu_pulse, that drives trace unit external output 1 on every traced cycle, so a PMU event counting it (TRCEXTOUT1) can end a fixed-length ETM window, for example with aux-action=pause. The feature only loads on ETMs whose PMU counts that output.

Changes in v2:
- Split the -EINVAL fix for a configuration that is active but not loaded on the device into its own patch, with a Fixes tag and an early return (Leo).
- Match capability flags separately from the device class: a feature loads on a device that shares one of its classes and has all of its capabilities, checked once in cscfg_load_feat_csdev() (Leo).
- Report each external output the PMU counts, TRCEXTOUT0-3, instead of only output 1 (Leo).
- Detect the outputs from TRCIDR0.NUMEVENT and PMCEID0_EL0, and drop the MIDR list (Leo, James).
- extout_pulse requires CS_CFG_MATCH_CLASS_SRC_ETM4 and CS_CFG_MATCH_CAP_PMU_EXTOUT(1). It still uses event and output 1:
event 0 is the trace unit trigger, which the TRBE driver treats as fatal (James).
- Link to v1: https://lore.kernel.org/r/[email protected]

Tested on Grace/Neoverse V2, pmu_pulse config loaded successfully.

Amir Ayupov (4):
coresight: syscfg: Fail to enable a configuration not loaded on the
device
coresight: syscfg: Match feature capabilities separately from device
class
coresight: etm4x: Report the external outputs the PMU counts
coresight: Add pmu_pulse/extout_pulse

 .../trace/coresight/coresight-config.rst      |  5 ++
 .../trace/coresight/coresight-perf.rst        | 19 ++++
 drivers/hwtracing/coresight/Makefile          |  1 +
 .../coresight/coresight-cfg-pmu-pulse.c       | 55 ++++++++++++
 .../coresight/coresight-cfg-preload.c         |  2 +
 .../coresight/coresight-cfg-preload.h         |  2 +
 .../hwtracing/coresight/coresight-config.h    | 10 +++
 .../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 ++
 .../hwtracing/coresight/coresight-syscfg.c    | 88 +++++++++++--------
 12 files changed, 193 insertions(+), 36 deletions(-)
 create mode 100644 drivers/hwtracing/coresight/coresight-cfg-pmu-pulse.c

base-commit: bc01105ed65d15787b2eb93ac26e8624a2139e35

Signature · 1 line
2.52.0
#1 lore raw

PATCH v2 1/4 coresight: syscfg: Fail to enable a configuration not loaded on the device

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
---
 .../hwtracing/coresight/coresight-syscfg.c    | 53 ++++++++++---------
 1 file changed, 28 insertions(+), 25 deletions(-)
drivers/hwtracing/coresight/coresight-syscfg.c +28 -25
index 2bfdd7b45e49c..a816c22c87bc8 100644
@@ -1088,36 +1088,39 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
 	raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
 
 	/*
-	 * If found, attempt to enable
+	 * The configuration is active but not loaded on this device, because
+	 * none of its features match the device. Fail rather than trace
+	 * without it.
 	 */
-	if (config_csdev_active) {
+	if (!config_csdev_active)
+		return -EINVAL;
+
+	/*
+	 * Call the generic routine that will program up the internal
+	 * driver structures prior to programming up the hardware.
+	 * This routine takes the driver spinlock saved in the configs.
+	 */
+	err = cscfg_csdev_enable_config(config_csdev_active, preset);
+	if (!err) {
 		/*
-		 * Call the generic routine that will program up the internal
-		 * driver structures prior to programming up the hardware.
-		 * This routine takes the driver spinlock saved in the configs.
+		 * Successful programming. Check the active_cscfg_ctxt
+		 * pointer to ensure no pre-emption disabled it via
+		 * cscfg_csdev_disable_active_config() before
+		 * we could start.
+		 *
+		 * Set enabled if OK, err if not.
 		 */
-		err = cscfg_csdev_enable_config(config_csdev_active, preset);
-		if (!err) {
-			/*
-			 * Successful programming. Check the active_cscfg_ctxt
-			 * pointer to ensure no pre-emption disabled it via
-			 * cscfg_csdev_disable_active_config() before
-			 * we could start.
-			 *
-			 * Set enabled if OK, err if not.
-			 */
-			raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
-			if (csdev->active_cscfg_ctxt)
-				config_csdev_active->enabled = true;
-			else
-				err = -EBUSY;
-			raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
-		}
-
-		if (err)
-			cscfg_config_desc_put(config_desc);
+		raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
+		if (csdev->active_cscfg_ctxt)
+			config_csdev_active->enabled = true;
+		else
+			err = -EBUSY;
+		raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
 	}
 
+	if (err)
+		cscfg_config_desc_put(config_desc);
+
 	return err;
 }
 EXPORT_SYMBOL_GPL(cscfg_csdev_enable_active_config);
Signature · 1 line
2.52.0
reviewer Reviewed-by on v2 1/4
#2 lore raw

Re: [PATCH v2 1/4] coresight: syscfg: Fail to enable a configuration not loaded on the device

Quoted 6 lines · Amir Ayupov

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.

Quoted 7 lines

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
reviewer
#3 lore raw

RE: [PATCH v2 1/4] coresight: syscfg: Fail to enable a configuration not loaded on the device

In reply to Amir Ayupov

Hi,

Quoted 21 lines

-----Original Message-----
From: Amir Ayupov <[email protected]>
Sent: Tuesday, October 13, 2026 12:05 AM
To: James Clark <[email protected]>; Leo Yan <[email protected]>; Suzuki Poulose <[email protected]>; Mike Leach <[email protected]>; Alexander Shishkin <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>; Jonathan Corbet <[email protected]>; Mathieu Poirier <[email protected]>; Randy Dunlap <[email protected]>; Shuah Khan <[email protected]>; [email protected]; [email protected]; linux- [email protected]; [email protected]
Subject: [PATCH v2 1/4] coresight: syscfg: Fail to enable a configuration not loaded on the device

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.

Quoted 4 lines

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.

If you look at the original comments - the idea of this function is to enable a configuration on a device if it is present on that device. Not enabling a configuration is _not_ an error. This is a generic function that can cover multiple classes of coresight device.

Moving forwards matching configurations to devices can omit certain devices from the configuration.

For example, a system will have many CTIs, but we may only want to use a specific one or two - possibly to connect etm external outputs to trigger a PE interrupt. Thus the remaining CTIs would not be active in this configuration.

This conflicts with your purpose which I assume is to prevent perf from using ETM sources that cannot load the required configuration.

I think what is actually needed is a "can_activate" function to be run on the ETM/ETE sources at etm_setup_aux time so that none compliant devices can be filtered out of the active cpu mask at that point.

Regards

Mike

Quoted 84 lines
Fixes f8cce2ff3c04 ("coresight: syscfg: Add API to activate and enable

configurations")

Assisted-by Devmate:Opus-5.5
---
 .../hwtracing/coresight/coresight-syscfg.c    | 53 ++++++++++---------
 1 file changed, 28 insertions(+), 25 deletions(-)
drivers/hwtracing/coresight/coresight-syscfg.c +19 -9
index 2bfdd7b45e49c..a816c22c87bc8 100644
@@ -1088,36 +1088,39 @@ int cscfg_csdev_enable_active_config(struct
 coresight_device *csdev,
 	raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
 
 	/*
-	 * If found, attempt to enable
+	 * The configuration is active but not loaded on this device, because
+	 * none of its features match the device. Fail rather than trace
+	 * without it.
 	 */
-	if (config_csdev_active) {
+	if (!config_csdev_active)
+		return -EINVAL;
+
+	/*
+	 * Call the generic routine that will program up the internal
+	 * driver structures prior to programming up the hardware.
+	 * This routine takes the driver spinlock saved in the configs.
+	 */
+	err = cscfg_csdev_enable_config(config_csdev_active, preset);
+	if (!err) {
 		/*
-		 * Call the generic routine that will program up the internal
-		 * driver structures prior to programming up the hardware.
-		 * This routine takes the driver spinlock saved in the configs.
+		 * Successful programming. Check the active_cscfg_ctxt
+		 * pointer to ensure no pre-emption disabled it via
+		 * cscfg_csdev_disable_active_config() before
+		 * we could start.
+		 *
+		 * Set enabled if OK, err if not.
 		 */
-		err = cscfg_csdev_enable_config(config_csdev_active, preset);
-		if (!err) {
-			/*
-			 * Successful programming. Check the

active_cscfg_ctxt

drivers/hwtracing/coresight/coresight-syscfg.c +0 -7
-			 * pointer to ensure no pre-emption disabled it via
-			 * cscfg_csdev_disable_active_config() before
-			 * we could start.
-			 *
-			 * Set enabled if OK, err if not.
-			 */
-			raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock,

flags);

drivers/hwtracing/coresight/coresight-syscfg.c +0 -5
-			if (csdev->active_cscfg_ctxt)
-				config_csdev_active->enabled = true;
-			else
-				err = -EBUSY;
-			raw_spin_unlock_irqrestore(&csdev-
Quoted 1 line

cscfg_csdev_lock, flags);

drivers/hwtracing/coresight/coresight-syscfg.c +9 -5
-		}
-
-		if (err)
-			cscfg_config_desc_put(config_desc);
+		raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
+		if (csdev->active_cscfg_ctxt)
+			config_csdev_active->enabled = true;
+		else
+			err = -EBUSY;
+		raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
 	}
 
+	if (err)
+		cscfg_config_desc_put(config_desc);
+
 	return err;
 }
 EXPORT_SYMBOL_GPL(cscfg_csdev_enable_active_config);
--

2.52.0

#4 lore raw

PATCH v2 2/4 coresight: syscfg: Match feature capabilities separately from device class

In reply to Amir Ayupov

A feature loads on a device when the two share any match flag. That works for device classes, where a feature wants any one of them, but not for capabilities a device may or may not have: a feature that sets a class and a capability would still load on a device of that class without the capability.

Reserve CS_CFG_MATCH_CAP_MASK for capability flags. A feature now loads on a device that shares one of its other flags and has all of its capabilities. Check this once in cscfg_load_feat_csdev(), which both the feature and the device registration paths call. No capability flags are defined yet, so matching is unchanged.

Assisted-by Devmate:Opus-5.5
---
 .../hwtracing/coresight/coresight-config.h    |  6 ++++
 .../hwtracing/coresight/coresight-syscfg.c    | 35 +++++++++++++------
 2 files changed, 31 insertions(+), 10 deletions(-)
drivers/hwtracing/coresight/coresight-config.h +6 -0
index 90fd937d3bd83..af6ef96b9ae01 100644
@@ -30,6 +30,12 @@
 #define CS_CFG_MATCH_CLASS_SRC_ALL	0x0001	/* match any source */
 #define CS_CFG_MATCH_CLASS_SRC_ETM4	0x0002	/* match any ETMv4 device */
 
+/*
+ * flags defining device capabilities a feature can require. A feature loads on
+ * a device that matches one of its classes and has all of its capabilities.
+ */
+#define CS_CFG_MATCH_CAP_MASK		0x0000ff00
+
 /* flags defining device instance matching - used in config match desc data. */
 #define CS_CFG_MATCH_INST_ANY		0x80000000 /* any instance of a class */
 
drivers/hwtracing/coresight/coresight-syscfg.c +25 -10
index a816c22c87bc8..1545d64afec01 100644
@@ -172,7 +172,21 @@ cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc
 }
 
 /* load one feature into one coresight device */
+/*
+ * A feature matches a device that shares one of its class flags and has all of
+ * the capability flags it requires.
+ */
+static bool cscfg_match_feat_csdev(u32 feat_flags, u32 csdev_flags)
+{
+	u32 caps = feat_flags & CS_CFG_MATCH_CAP_MASK;
+
+	return (feat_flags & csdev_flags & ~CS_CFG_MATCH_CAP_MASK) &&
+	       (csdev_flags & caps) == caps;
+}
+
+/* Load the feature into the device if it matches, otherwise skip it. */
 static int cscfg_load_feat_csdev(struct coresight_device *csdev,
+				 u32 match_flags,
 				 struct cscfg_feature_desc *feat_desc,
 				 struct cscfg_csdev_feat_ops *ops)
 {
@@ -183,6 +197,9 @@ static int cscfg_load_feat_csdev(struct coresight_device *csdev,
 	if (!ops->load_feat)
 		return -EINVAL;
 
+	if (!cscfg_match_feat_csdev(feat_desc->match_flags, match_flags))
+		return 0;
+
 	feat_csdev = cscfg_alloc_csdev_feat(csdev, feat_desc);
 	if (!feat_csdev)
 		return -ENOMEM;
@@ -212,11 +229,11 @@ static int cscfg_add_feat_to_csdevs(struct cscfg_feature_desc *feat_desc)
 	int err;
 
 	list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
-		if (csdev_item->match_flags & feat_desc->match_flags) {
-			err = cscfg_load_feat_csdev(csdev_item->csdev, feat_desc, &csdev_item->ops);
-			if (err)
-				return err;
-		}
+		err = cscfg_load_feat_csdev(csdev_item->csdev,
+					    csdev_item->match_flags, feat_desc,
+					    &csdev_item->ops);
+		if (err)
+			return err;
 	}
 	return 0;
 }
@@ -739,11 +756,9 @@ static int cscfg_add_feats_csdev(struct coresight_device *csdev,
 		return -EINVAL;
 
 	list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
-		if (feat_desc->match_flags & match_flags) {
-			err = cscfg_load_feat_csdev(csdev, feat_desc, ops);
-			if (err)
-				break;
-		}
+		err = cscfg_load_feat_csdev(csdev, match_flags, feat_desc, ops);
+		if (err)
+			break;
 	}
 	return err;
 }
Signature · 1 line
2.52.0
reviewer
#5 lore raw

Re: [PATCH v2 2/4] coresight: syscfg: Match feature capabilities separately from device class

On Mon, Oct 12, 2026 at 04:05:21PM -0700, Amir Ayupov wrote:

[...]

drivers/hwtracing/coresight/coresight-config.h line 31

Quoted 5 lines
drivers/hwtracing/coresight/coresight-config.h +0 -0
@@ -30,6 +30,12 @@
 #define CS_CFG_MATCH_CLASS_SRC_ALL	0x0001	/* match any source */
 #define CS_CFG_MATCH_CLASS_SRC_ETM4	0x0002	/* match any ETMv4 device */

It is good to introduce a marco:

  #define CS_CFG_MATCH_CLASS_MASK       GENMASK_U32(7, 0)

drivers/hwtracing/coresight/coresight-config.h line 37

Quoted 5 lines
drivers/hwtracing/coresight/coresight-config.h +5 -0
+/*
+ * flags defining device capabilities a feature can require. A feature loads on
+ * a device that matches one of its classes and has all of its capabilities.
+ */
+#define CS_CFG_MATCH_CAP_MASK		0x0000ff00

To make the mask explicitly 32-bit unsigned:

  #define CS_CFG_MATCH_CAP_MASK		GENMASK_U32(15, 8)

drivers/hwtracing/coresight/coresight-config.h line 40

Quoted 3 lines
drivers/hwtracing/coresight/coresight-config.h +1 -0
+
 /* flags defining device instance matching - used in config match desc data. */
 #define CS_CFG_MATCH_INST_ANY		0x80000000 /* any instance of a class */

Not an issue with this patch, but CS_CFG_MATCH_INST_ANY appears to be unused and could be removed in a separate cleanup patch.

Quoted 8 lines
drivers/hwtracing/coresight/coresight-syscfg.c +0 -0
index a816c22c87bc8..1545d64afec01 100644
@@ -172,7 +172,21 @@ cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc
 }
 
 /* load one feature into one coresight device */

drivers/hwtracing/coresight/coresight-syscfg.c cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc · line 184

Quoted 10 lines
drivers/hwtracing/coresight/coresight-syscfg.c +10 -0
+/*
+ * A feature matches a device that shares one of its class flags and has all of
+ * the capability flags it requires.
+ */
+static bool cscfg_match_feat_csdev(u32 feat_flags, u32 csdev_flags)
+{
+	u32 caps = feat_flags & CS_CFG_MATCH_CAP_MASK;
+
+	return (feat_flags & csdev_flags & ~CS_CFG_MATCH_CAP_MASK) &&
+	       (csdev_flags & caps) == caps;

For clearer comparison conditions:

       /* Class type must be matches */
       if ((feat_flags & CS_CFG_MATCH_CLASS_MASK) !=
           (csdev_flags & CS_CFG_MATCH_CLASS_MASK)
           return false;

       /* No required capabilities miss from the device */
       if (feat_flags & ~csdev_flags & CS_CFG_MATCH_CAP_MASK)
           return false;

       return true;

Thanks,
Leo

#6 lore raw

Re: [PATCH v2 2/4] coresight: syscfg: Match feature capabilities separately from device class

Quoted 22 lines · On Wed, 21 Oct 2026 15:39:58 +0100 Leo Yan <[email protected]> wrote:

On Mon, Oct 12, 2026 at 04:05:21PM -0700, Amir Ayupov wrote:

[...]

drivers/hwtracing/coresight/coresight-config.h line 31

Quoted 5 lines
drivers/hwtracing/coresight/coresight-config.h +0 -0
@@ -30,6 +30,12 @@
 #define CS_CFG_MATCH_CLASS_SRC_ALL	0x0001	/* match any source */
 #define CS_CFG_MATCH_CLASS_SRC_ETM4	0x0002	/* match any ETMv4 device */

It is good to introduce a marco:

  #define CS_CFG_MATCH_CLASS_MASK       GENMASK_U32(7, 0)

drivers/hwtracing/coresight/coresight-config.h line 37

Quoted 5 lines
drivers/hwtracing/coresight/coresight-config.h +5 -0
+/*
+ * flags defining device capabilities a feature can require. A feature loads on
+ * a device that matches one of its classes and has all of its capabilities.
+ */
+#define CS_CFG_MATCH_CAP_MASK		0x0000ff00

To make the mask explicitly 32-bit unsigned:

Quoted 2 lines
  #define CS_CFG_MATCH_CAP_MASK		GENMASK_U32(15, 8)

Thanks, will apply in v3.

Quoted 7 lines

drivers/hwtracing/coresight/coresight-config.h line 40

Quoted 3 lines
drivers/hwtracing/coresight/coresight-config.h +1 -0
+
 /* flags defining device instance matching - used in config match desc data. */
 #define CS_CFG_MATCH_INST_ANY		0x80000000 /* any instance of a class */

Not an issue with this patch, but CS_CFG_MATCH_INST_ANY appears to be unused and could be removed in a separate cleanup patch.

Will drop in a separate patch in v3.

Quoted 32 lines
Quoted 8 lines
drivers/hwtracing/coresight/coresight-syscfg.c +0 -0
index a816c22c87bc8..1545d64afec01 100644
@@ -172,7 +172,21 @@ cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc
 }
 
 /* load one feature into one coresight device */

drivers/hwtracing/coresight/coresight-syscfg.c cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc · line 184

Quoted 10 lines
drivers/hwtracing/coresight/coresight-syscfg.c +10 -0
+/*
+ * A feature matches a device that shares one of its class flags and has all of
+ * the capability flags it requires.
+ */
+static bool cscfg_match_feat_csdev(u32 feat_flags, u32 csdev_flags)
+{
+	u32 caps = feat_flags & CS_CFG_MATCH_CAP_MASK;
+
+	return (feat_flags & csdev_flags & ~CS_CFG_MATCH_CAP_MASK) &&
+	       (csdev_flags & caps) == caps;

For clearer comparison conditions:

       /* Class type must be matches */
       if ((feat_flags & CS_CFG_MATCH_CLASS_MASK) !=
           (csdev_flags & CS_CFG_MATCH_CLASS_MASK)
           return false;

       /* No required capabilities miss from the device */
       if (feat_flags & ~csdev_flags & CS_CFG_MATCH_CAP_MASK)
           return false;

       return true;
Quoted 2 lines

Thanks,
Leo

Yes, that looks cleaner, thanks!

Sent using hkml (https://github.com/sjp38/hackermail)

maintainer
#7 lore raw

Re: [PATCH v2 2/4] coresight: syscfg: Match feature capabilities separately from device class

In reply to Leo Yan
Quoted 52 lines · Leo Yan

On Mon, Oct 12, 2026 at 04:05:21PM -0700, Amir Ayupov wrote:

[...]

drivers/hwtracing/coresight/coresight-config.h line 31

Quoted 5 lines
drivers/hwtracing/coresight/coresight-config.h +0 -0
@@ -30,6 +30,12 @@
  #define CS_CFG_MATCH_CLASS_SRC_ALL	0x0001	/* match any source */
  #define CS_CFG_MATCH_CLASS_SRC_ETM4	0x0002	/* match any ETMv4 device */

It is good to introduce a marco:

   #define CS_CFG_MATCH_CLASS_MASK       GENMASK_U32(7, 0)

drivers/hwtracing/coresight/coresight-config.h line 37

Quoted 5 lines
drivers/hwtracing/coresight/coresight-config.h +5 -0
+/*
+ * flags defining device capabilities a feature can require. A feature loads on
+ * a device that matches one of its classes and has all of its capabilities.
+ */
+#define CS_CFG_MATCH_CAP_MASK		0x0000ff00

To make the mask explicitly 32-bit unsigned:

   #define CS_CFG_MATCH_CAP_MASK		GENMASK_U32(15, 8)

drivers/hwtracing/coresight/coresight-config.h line 40

Quoted 3 lines
drivers/hwtracing/coresight/coresight-config.h +1 -0
+
  /* flags defining device instance matching - used in config match desc data. */
  #define CS_CFG_MATCH_INST_ANY		0x80000000 /* any instance of a class */

Not an issue with this patch, but CS_CFG_MATCH_INST_ANY appears to be unused and could be removed in a separate cleanup patch.

Quoted 8 lines
drivers/hwtracing/coresight/coresight-syscfg.c +0 -0
index a816c22c87bc8..1545d64afec01 100644
@@ -172,7 +172,21 @@ cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc
  }
 
  /* load one feature into one coresight device */

drivers/hwtracing/coresight/coresight-syscfg.c cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc · line 184

Quoted 10 lines
drivers/hwtracing/coresight/coresight-syscfg.c +10 -0
+/*
+ * A feature matches a device that shares one of its class flags and has all of
+ * the capability flags it requires.
+ */
+static bool cscfg_match_feat_csdev(u32 feat_flags, u32 csdev_flags)
+{
+	u32 caps = feat_flags & CS_CFG_MATCH_CAP_MASK;
+
+	return (feat_flags & csdev_flags & ~CS_CFG_MATCH_CAP_MASK) &&
+	       (csdev_flags & caps) == caps;

For clearer comparison conditions:

Quoted 4 lines
        /* Class type must be matches */
        if ((feat_flags & CS_CFG_MATCH_CLASS_MASK) !=
            (csdev_flags & CS_CFG_MATCH_CLASS_MASK)
            return false;

Why not use FIELD_GET() to compare to make it more explicit ?

Quoted 4 lines
        /* No required capabilities miss from the device */
        if (feat_flags & ~csdev_flags & CS_CFG_MATCH_CAP_MASK)
            return false;

Same here.

Suzuki>

Quoted 4 lines
        return true;

Thanks,
Leo

#8 lore raw

PATCH v2 3/4 coresight: etm4x: Report the external outputs the PMU counts

In reply to Amir Ayupov

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
---
 .../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(-)
drivers/hwtracing/coresight/coresight-config.h +4 -0
index af6ef96b9ae01..10e95f5ecc8d9 100644
@@ -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 */
drivers/hwtracing/coresight/coresight-etm4x-cfg.c +4 -1
index e1a59b4345052..09a7a6b86968c 100644
@@ -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);
 }
drivers/hwtracing/coresight/coresight-etm4x-core.c +32 -0
index 2247ad55d4442..1e78774025d13 100644
@@ -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);
+	}
+
+	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);
drivers/hwtracing/coresight/coresight-etm4x.h +3 -0
index df9e0748d71ec..11d95a4518b88 100644
@@ -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;
drivers/hwtracing/coresight/coresight-syscfg-configfs.c +7 -0
index 2b40e556be872..7893d40f2e9ea 100644
@@ -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;
 }
Signature · 1 line
2.52.0
reviewer
#9 lore raw

Re: [PATCH v2 3/4] coresight: etm4x: Report the external outputs the PMU counts

On Mon, Oct 12, 2026 at 04:05:22PM -0700, Amir Ayupov wrote:

[...]

drivers/hwtracing/coresight/coresight-config.h line 41

Quoted 10 lines
drivers/hwtracing/coresight/coresight-config.h +4 -0
@@ -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)

drivers/hwtracing/coresight/coresight-config.h

Quoted 11 lines
drivers/hwtracing/coresight/coresight-config.h +4 -1
 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 <[email protected]>
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.

---
 .../coresight/coresight-etm4x-core.c          | 13 +++++++--
 .../coresight/coresight-etm4x-sysfs.c         | 29 ++++++++++---------
 2 files changed, 27 insertions(+), 15 deletions(-)
drivers/hwtracing/coresight/coresight-etm4x-core.c +11 -2
index e21be6468e954..af017bd8a5477 100644
@@ -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
drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +16 -13
index db9e603f97ba8..fb38f0102290a 100644
@@ -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 |
Signature · 1 line
2.34.1
reviewer
#10 lore raw

Re: [PATCH v2 3/4] coresight: etm4x: Report the external outputs the PMU counts

Quoted 4 lines · Leo Yan

On Mon, Oct 12, 2026 at 04:05:22PM -0700, Amir Ayupov wrote:

[...]

Quoted 10 lines

drivers/hwtracing/coresight/coresight-config.h line 41

Quoted 10 lines
drivers/hwtracing/coresight/coresight-config.h +4 -0
@@ -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))

Isn't this recreating what GENMASK() and FIELD_PREP() does? Can we use that instead?

Quoted 20 lines

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)

drivers/hwtracing/coresight/coresight-config.h

Quoted 11 lines
drivers/hwtracing/coresight/coresight-config.h +4 -1
  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:

Quoted 6 lines
   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.

ETE only makes sense to me.

Quoted 134 lines

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 <[email protected]>
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.

---
  .../coresight/coresight-etm4x-core.c          | 13 +++++++--
  .../coresight/coresight-etm4x-sysfs.c         | 29 ++++++++++---------
  2 files changed, 27 insertions(+), 15 deletions(-)
drivers/hwtracing/coresight/coresight-etm4x-core.c +11 -2
index e21be6468e954..af017bd8a5477 100644
@@ -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
drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +16 -13
index db9e603f97ba8..fb38f0102290a 100644
@@ -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 |
reviewer
#11 lore raw

Re: [PATCH v2 3/4] coresight: etm4x: Report the external outputs the PMU counts

On Fri, Oct 23, 2026 at 10:49:40AM +0100, James Clark wrote:

[...]

Quoted 10 lines
Quoted 7 lines

Review

Quoted 7 lines

* a device that matches one of its classes and has all of its capabilities. */
#define CS_CFG_MATCH_CAP_MASK 0x0000ff00

(quoted diff) +4 -0
+/* 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))

Isn't this recreating what GENMASK() and FIELD_PREP() does? Can we use that instead?

TBC, are you suggesting using separate capability bits to represent TRCEXTOUT0-3? Why can't we use a single capability bit to indicate whether the feature is supported and caps->num_event to indicate the number of external output signals?

reviewer
#12 lore raw

Re: [PATCH v2 3/4] coresight: etm4x: Report the external outputs the PMU counts

Quoted 15 lines · Leo Yan

On Fri, Oct 23, 2026 at 10:49:40AM +0100, James Clark wrote:

[...]

Quoted 10 lines
Quoted 7 lines

Review

Quoted 7 lines

* a device that matches one of its classes and has all of its capabilities. */
#define CS_CFG_MATCH_CAP_MASK 0x0000ff00

(quoted diff) +4 -0
+/* 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))

Isn't this recreating what GENMASK() and FIELD_PREP() does? Can we use that instead?

Quoted 4 lines

TBC, are you suggesting using separate capability bits to represent TRCEXTOUT0-3? Why can't we use a single capability bit to indicate whether the feature is supported and caps->num_event to indicate the number of external output signals?

Just the pattern of *_SHIFT and other stuff to make a bitfield is usually better done with GENMASK(). Or if there are only 4 of them, even defining four BIT()s would be clearer.

But yes if a single bit and caps->num_event works we should do that instead.

#13 lore raw

Re: [PATCH v2 3/4] coresight: etm4x: Report the external outputs the PMU counts

In reply to Leo Yan
Quoted 18 lines · On Wed, 21 Oct 2026 17:43:32 +0100 Leo Yan <[email protected]> wrote:

On Mon, Oct 12, 2026 at 04:05:22PM -0700, Amir Ayupov wrote:

[...]

drivers/hwtracing/coresight/coresight-config.h line 41

Quoted 10 lines
drivers/hwtracing/coresight/coresight-config.h +4 -0
@@ -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:

Quoted 2 lines
  #define CS_CFG_MATCH_CAP_TRCEXTOUT            BIT(8)

Yes, single bit works.

Quoted 14 lines

drivers/hwtracing/coresight/coresight-config.h

Quoted 11 lines
drivers/hwtracing/coresight/coresight-config.h +4 -1
 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:

Quoted 6 lines

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.

I'll keep an extra condition that PMU must also implement TRCEXTOUT for each of the nr_events outputs. Otherwise it'll start but the pause event would never fire. I'll also use pmuv3_event_implemented helper suggested by James but let me know if I should just check is_ete && nr_events.

Quoted 5 lines

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.

Rebased in v3.

Quoted 131 lines

[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 <[email protected]>
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.

---
 .../coresight/coresight-etm4x-core.c          | 13 +++++++--
 .../coresight/coresight-etm4x-sysfs.c         | 29 ++++++++++---------
 2 files changed, 27 insertions(+), 15 deletions(-)
drivers/hwtracing/coresight/coresight-etm4x-core.c +11 -2
index e21be6468e954..af017bd8a5477 100644
@@ -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
drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +16 -13
index db9e603f97ba8..fb38f0102290a 100644
@@ -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 |
Signature · 1 line
2.34.1

Sent using hkml (https://github.com/sjp38/hackermail)

reviewer
#14 lore raw

Re: [PATCH v2 3/4] coresight: etm4x: Report the external outputs the PMU counts

In reply to Amir Ayupov
Quoted 94 lines · Amir Ayupov

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
---
  .../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(-)
drivers/hwtracing/coresight/coresight-config.h +4 -0
index af6ef96b9ae01..10e95f5ecc8d9 100644
@@ -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 */
drivers/hwtracing/coresight/coresight-etm4x-cfg.c +4 -1
index e1a59b4345052..09a7a6b86968c 100644
@@ -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);
  }
drivers/hwtracing/coresight/coresight-etm4x-core.c +16 -0
index 2247ad55d4442..1e78774025d13 100644
@@ -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;
+

drivers/hwtracing/coresight/coresight-etm4x-core.c static void etm4_fixup_wrong_ccitmin(struct etmv4_drvdata *drvdata) · line 1396

Quoted 10 lines
drivers/hwtracing/coresight/coresight-etm4x-core.c +10 -0
+	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.

Quoted 62 lines
drivers/hwtracing/coresight/coresight-etm4x-core.c +6 -0
+
+	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);
drivers/hwtracing/coresight/coresight-etm4x.h +3 -0
index df9e0748d71ec..11d95a4518b88 100644
@@ -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;
drivers/hwtracing/coresight/coresight-syscfg-configfs.c +7 -0
index 2b40e556be872..7893d40f2e9ea 100644
@@ -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;
  }
reviewer
#15 lore raw

RE: [PATCH v2 3/4] coresight: etm4x: Report the external outputs the PMU counts

In reply to Amir Ayupov

Hi,

Quoted 29 lines

-----Original Message-----
From: Amir Ayupov <[email protected]>
Sent: Tuesday, October 13, 2026 12:05 AM
To: James Clark <[email protected]>; Leo Yan <[email protected]>; Suzuki Poulose <[email protected]>; Mike Leach <[email protected]>; Alexander Shishkin <[email protected]>
Cc: Jonathan Corbet <[email protected]>; Randy Dunlap <[email protected]>; Shuah Khan <[email protected]>; [email protected]; [email protected]; linux- [email protected]; [email protected]
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.

Quoted 7 lines

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

Quoted 92 lines
Assisted-by Devmate:Opus-5.5
---
 .../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(-)
drivers/hwtracing/coresight/coresight-config.h +3 -0
index af6ef96b9ae01..10e95f5ecc8d9 100644
@@ -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 */

drivers/hwtracing/coresight/coresight-etm4x-cfg.c +3 -1
index e1a59b4345052..09a7a6b86968c 100644
@@ -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);

drivers/hwtracing/coresight/coresight-etm4x-cfg.c +1 -0
+	return cscfg_register_csdev(csdev, match_flags, &ops);
 }
drivers/hwtracing/coresight/coresight-etm4x-core.c +4 -0
index 2247ad55d4442..1e78774025d13 100644
@@ -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.
+ */

drivers/hwtracing/coresight/coresight-etm4x-core.c +8 -0
+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)

drivers/hwtracing/coresight/coresight-etm4x-core.c +4 -0
+		return 0;
+
+	pmceid = read_pmceid0() >> 32;
+	/* nr_event is TRCIDR0.NUMEVENT, the number of events minus one
Quoted 1 line

*/

Not necessarily - this value depends on the ETM version.

Quoted 40 lines
drivers/hwtracing/coresight/coresight-etm4x-core.c +2 -0
+	for (n = 0; n <= drvdata->nr_event; n++) {
+		if (pmceid &

BIT_ULL(ARMV8_PMUV3_PERFCTR_TRCEXTOUT0 + n -
+
ARMV8_PMUV3_EXT_COMMON_EVENT_BASE))

drivers/hwtracing/coresight/coresight-etm4x-core.c +8 -0
+			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);
drivers/hwtracing/coresight/coresight-etm4x.h +1 -0
index df9e0748d71ec..11d95a4518b88 100644
@@ -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.

drivers/hwtracing/coresight/coresight-etm4x.h struct etmv4_drvdata { · line 1050

Quoted 4 lines
drivers/hwtracing/coresight/coresight-etm4x.h +1 -0
@@ -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.

Quoted 35 lines
drivers/hwtracing/coresight/coresight-etm4x.h +0 -0
 	u8				nr_resource;
 	u8				nr_ss_cmp;
 	u8				trcid;
drivers/hwtracing/coresight/coresight-syscfg-configfs.c +1 -0
index 2b40e556be872..7893d40f2e9ea 100644
@@ -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;
 
drivers/hwtracing/coresight/coresight-syscfg-configfs.c +6 -0
 	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

#16 lore raw

PATCH v2 4/4 coresight: Add pmu_pulse/extout_pulse

In reply to Amir Ayupov

Add ETMv4 configuration 'pmu_pulse' with 'extout_pulse' feature which requires an ETM whose PMU counts external output 1 (CS_CFG_MATCH_CAP_PMU_EXTOUT(1)): event 1 selects the always-true resource and drives TRCEXTOUT1 PMU event which pulses on every cycle while the trace unit is enabled.

The intended use is for CSSPGO profiling: a fixed-length ETM strobing window that ends at a PMU event. The window is decoded into branch stack, PMU event is carrying callchains. pmu_pulse allows specifying the window in ETM cycles.

Assisted-by Devmate:Opus-5.5
---
 .../trace/coresight/coresight-config.rst      |  5 ++
 .../trace/coresight/coresight-perf.rst        | 19 +++++++
 drivers/hwtracing/coresight/Makefile          |  1 +
 .../coresight/coresight-cfg-pmu-pulse.c       | 55 +++++++++++++++++++
 .../coresight/coresight-cfg-preload.c         |  2 +
 .../coresight/coresight-cfg-preload.h         |  2 +
 6 files changed, 84 insertions(+)
 create mode 100644 drivers/hwtracing/coresight/coresight-cfg-pmu-pulse.c
Documentation/trace/coresight/coresight-config.rst +5 -0
index 6d5ffa6f73471..3eed728bf0de1 100644
@@ -129,6 +129,11 @@ The following steps take place in the operation of a configuration.
 
 5) At the end of the perf session, the configuration will be disabled.
 
+The built-in 'pmu_pulse' configuration pulses ETM external output 1 for a PMU
+event to count. It only pulses while the ETM is enabled, so combined with AUX
+pause and resume the PMU event can time each trace window (see
+coresight-perf.rst).
+
 
 Viewing Configurations and Features
 ===================================
Documentation/trace/coresight/coresight-perf.rst +19 -0
index 0a77741a431ef..7163d206f9b36 100644
@@ -109,6 +109,25 @@ Example for triggering AUX pause and resume with PMU event::
         -e cycles/aux-action=pause,period=10000000/ \
         -e cycles/aux-action=resume,period=1050000/ -- sleep 1
 
+ETM-timed pause events
+~~~~~~~~~~~~~~~~~~~~~~
+
+The built-in ``pmu_pulse`` configuration pulses ETM external output 1 on every
+cycle of allowed trace, and a PMU event counting that output pauses trace after
+``N`` pulses, here 1000 cycles::
+
+  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
+
+Each window is about ``N`` traced cycles plus the pause interrupt latency, so
+windows are never empty and a callchain on the pause event is taken where
+trace ends. The configuration only loads where the PMU counts ETM external
+output 1, which the feature's configfs 'matches' attribute shows as
+PMU_EXTOUT1; elsewhere a session selecting it fails to start.
+
 Perf test - Verify kernel and userspace perf CoreSight work
 -----------------------------------------------------------
 
drivers/hwtracing/coresight/Makefile +1 -0
index ab16d06783a57..568e797ac5a17 100644
@@ -28,6 +28,7 @@ obj-$(CONFIG_CORESIGHT) += coresight.o
 coresight-y := coresight-core.o  coresight-etm-perf.o coresight-platform.o \
 		coresight-sysfs.o coresight-syscfg.o coresight-config.o \
 		coresight-cfg-preload.o coresight-cfg-afdo.o coresight-cfg-pstop.o \
+		coresight-cfg-pmu-pulse.o \
 		coresight-syscfg-configfs.o coresight-trace-id.o
 obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o
 coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \
drivers/hwtracing/coresight/coresight-cfg-pmu-pulse.c new file +55 -0

55 lines not on this page · raw message

drivers/hwtracing/coresight/coresight-cfg-preload.c +2 -0
index 4980e68483c5b..a9a60a1c40845 100644
@@ -14,6 +14,7 @@ static struct cscfg_feature_desc *preload_feats[] = {
 #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
 	&strobe_etm4x,
 	&gen_etrig_etm4x,
+	&extout_pulse_etm4x,
 #endif
 	NULL
 };
@@ -22,6 +23,7 @@ static struct cscfg_config_desc *preload_cfgs[] = {
 #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
 	&afdo_etm4x,
 	&pstop_etm4x,
+	&pmu_pulse_etm4x,
 #endif
 	NULL
 };
drivers/hwtracing/coresight/coresight-cfg-preload.h +2 -0
index 291ba530a6a52..0058627f65ae5 100644
@@ -12,4 +12,6 @@ extern struct cscfg_feature_desc strobe_etm4x;
 extern struct cscfg_config_desc afdo_etm4x;
 extern struct cscfg_feature_desc gen_etrig_etm4x;
 extern struct cscfg_config_desc pstop_etm4x;
+extern struct cscfg_feature_desc extout_pulse_etm4x;
+extern struct cscfg_config_desc pmu_pulse_etm4x;
 #endif
Signature · 1 line
2.52.0
Reviewed-by on v2 4/4
#17 lore raw

Re: [PATCH v2 4/4] coresight: Add pmu_pulse/extout_pulse

On Mon, Oct 12, 2026 at 04:05:23PM -0700, Amir Ayupov wrote:
[...]

Documentation/trace/coresight/coresight-perf.rst Example for triggering AUX pause and resume with PMU event:: · line 123

Quoted 5 lines
Documentation/trace/coresight/coresight-perf.rst +5 -0
+  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 applied the documentation hunks and built htmldocs, no new warnings. With or without the above, for the documentation part:

Thanks,
Daniel

#18 lore raw

Re: [PATCH v2 4/4] coresight: Add pmu_pulse/extout_pulse

Quoted 8 lines · On Mon, 12 Oct 2026 22:09:35 -0300 Daniel Pereira <[email protected]>…

On Mon, Oct 12, 2026 at 04:05:23PM -0700, Amir Ayupov wrote:
[...]

Documentation/trace/coresight/coresight-perf.rst Example for triggering AUX pause and resume with PMU event:: · line 123

Quoted 5 lines
Documentation/trace/coresight/coresight-perf.rst +5 -0
+  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
Quoted 7 lines

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.

Quoted 8 lines

I applied the documentation hunks and built htmldocs, no new warnings. With or without the above, for the documentation part:

Thanks,
Daniel

Sent using hkml (https://github.com/sjp38/hackermail)

reviewer
#19 lore raw

Re: [PATCH v2 4/4] coresight: Add pmu_pulse/extout_pulse

Quoted 15 lines · Amir Ayupov
Quoted 13 lines · On Mon, 12 Oct 2026 22:09:35 -0300 Daniel Pereira <[email protected]>…

On Mon, Oct 12, 2026 at 04:05:23PM -0700, Amir Ayupov wrote:
[...]

Documentation/trace/coresight/coresight-perf.rst Example for triggering AUX pause and resume with PMU event:: · line 123

Quoted 5 lines
Documentation/trace/coresight/coresight-perf.rst +5 -0
+  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:

Quoted 4 lines
Quoted 2 lines

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.

Quoted 10 lines
Quoted 8 lines

I applied the documentation hunks and built htmldocs, no new warnings. With or without the above, for the documentation part:

Thanks,
Daniel

Sent using hkml (https://github.com/sjp38/hackermail)

#20 lore raw

v3 cover coresight: Pulse an ETM external output for a PMU event

In reply to Amir Ayupov

Add an ETMv4 configuration, pmu_pulse, that drives trace unit external output 1 on every traced cycle, so a PMU event counting it (TRCEXTOUT1) can end a fixed-length ETM window, for example with aux-action=pause. The feature only loads on an ETE whose PMU counts its external outputs.

Patch 1 is Leo's fix for TRCIDR0.NUMEVENT decoding, which patch 6 relies on for the number of external outputs.

Changes in v3:
- Rebase onto coresight next, which moves the capability fields into drvdata->caps (Leo).
- Carry Leo's "coresight: etm4x: Fix event count decoding" (Leo).
- Add Leo's Reviewed-by to "Fail to enable a configuration not loaded on the device".
- Define CS_CFG_MATCH_CLASS_MASK and CS_CFG_MATCH_CAP_MASK with GENMASK_U32() and split the match check into early returns (Leo). The class check stays an intersection, as ETMv4 devices register with SRC_ALL | SRC_ETM4 while the built-in features only set SRC_ETM4.
- Remove the unused CS_CFG_MATCH_INST_ANY in a separate patch (Leo).
- Replace the per-output CS_CFG_MATCH_CAP_PMU_EXTOUT(n) bits with a single CS_CFG_MATCH_CAP_TRCEXTOUT, set on ETE only (Leo, James).
- Check the PMU events through a new pmuv3_event_implemented() helper instead of open-coding PMCEID0_EL0 in etm4x (James).
- Use PMU-agnostic event names in the documentation example (Daniel).
- Add Daniel's Reviewed-by to "Add pmu_pulse/extout_pulse".
- Link to v2: https://lore.kernel.org/r/[email protected]

Amir Ayupov (6):
coresight: syscfg: Fail to enable a configuration not loaded on the device
coresight: syscfg: Match feature capabilities separately from device class
coresight: syscfg: Remove unused CS_CFG_MATCH_INST_ANY
perf: arm_pmuv3: Add pmuv3_event_implemented()
coresight: etm4x: Report whether the PMU counts the external outputs
coresight: Add pmu_pulse/extout_pulse

Leo Yan (1):
coresight: etm4x: Fix event count decoding

 .../trace/coresight/coresight-config.rst      |  5 ++
 .../trace/coresight/coresight-perf.rst        | 15 ++++
 drivers/hwtracing/coresight/Makefile          |  1 +
 .../coresight/coresight-cfg-pmu-pulse.c       | 55 ++++++++++++
 .../coresight/coresight-cfg-preload.c         |  2 +
 .../coresight/coresight-cfg-preload.h         |  2 +
 .../hwtracing/coresight/coresight-config.h    | 11 ++-
 .../hwtracing/coresight/coresight-etm4x-cfg.c |  6 +-
 .../coresight/coresight-etm4x-core.c          | 39 +++++++-
 .../coresight/coresight-etm4x-sysfs.c         | 29 +++---
 drivers/hwtracing/coresight/coresight-etm4x.h |  3 +
 .../coresight/coresight-syscfg-configfs.c     |  3 +
 .../hwtracing/coresight/coresight-syscfg.c    | 90 +++++++++++--------
 include/linux/perf/arm_pmu.h                  |  1 -
 include/linux/perf/arm_pmuv3.h                | 22 +++++
 15 files changed, 229 insertions(+), 55 deletions(-)
 create mode 100644 drivers/hwtracing/coresight/coresight-cfg-pmu-pulse.c

base-commit: 343cfcbb3ecfdb80aa576a428cfa3b65ad783842

Signature · 1 line
2.52.0
#21 lore raw

PATCH v3 1/7 coresight: etm4x: Fix event count decoding

From: Leo Yan <[email protected]>

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.

---
 .../coresight/coresight-etm4x-core.c          | 13 +++++++--
 .../coresight/coresight-etm4x-sysfs.c         | 29 ++++++++++---------
 2 files changed, 27 insertions(+), 15 deletions(-)
drivers/hwtracing/coresight/coresight-etm4x-core.c +11 -2
index e21be6468e954..af017bd8a5477 100644
@@ -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
drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +16 -13
index db9e603f97ba8..fb38f0102290a 100644
@@ -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 |
Signature · 1 line
2.52.0
#22 lore raw

Re: [PATCH v3 1/7] coresight: etm4x: Fix event count decoding

Sashiko has reviewed this patch and found no issues.
Quoted 14 lines

From: Leo Yan <[email protected]>

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.

Quoted 8 lines

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.

Sashiko has reviewed this patch and found no issues.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
#23 lore raw

PATCH v3 2/7 coresight: syscfg: Fail to enable a configuration not loaded on the device

In reply to Amir Ayupov

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
---
 .../hwtracing/coresight/coresight-syscfg.c    | 53 ++++++++++---------
 1 file changed, 28 insertions(+), 25 deletions(-)
drivers/hwtracing/coresight/coresight-syscfg.c +28 -25
index 2bfdd7b45e49c..a816c22c87bc8 100644
@@ -1088,36 +1088,39 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
 	raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
 
 	/*
-	 * If found, attempt to enable
+	 * The configuration is active but not loaded on this device, because
+	 * none of its features match the device. Fail rather than trace
+	 * without it.
 	 */
-	if (config_csdev_active) {
+	if (!config_csdev_active)
+		return -EINVAL;
+
+	/*
+	 * Call the generic routine that will program up the internal
+	 * driver structures prior to programming up the hardware.
+	 * This routine takes the driver spinlock saved in the configs.
+	 */
+	err = cscfg_csdev_enable_config(config_csdev_active, preset);
+	if (!err) {
 		/*
-		 * Call the generic routine that will program up the internal
-		 * driver structures prior to programming up the hardware.
-		 * This routine takes the driver spinlock saved in the configs.
+		 * Successful programming. Check the active_cscfg_ctxt
+		 * pointer to ensure no pre-emption disabled it via
+		 * cscfg_csdev_disable_active_config() before
+		 * we could start.
+		 *
+		 * Set enabled if OK, err if not.
 		 */
-		err = cscfg_csdev_enable_config(config_csdev_active, preset);
-		if (!err) {
-			/*
-			 * Successful programming. Check the active_cscfg_ctxt
-			 * pointer to ensure no pre-emption disabled it via
-			 * cscfg_csdev_disable_active_config() before
-			 * we could start.
-			 *
-			 * Set enabled if OK, err if not.
-			 */
-			raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
-			if (csdev->active_cscfg_ctxt)
-				config_csdev_active->enabled = true;
-			else
-				err = -EBUSY;
-			raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
-		}
-
-		if (err)
-			cscfg_config_desc_put(config_desc);
+		raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
+		if (csdev->active_cscfg_ctxt)
+			config_csdev_active->enabled = true;
+		else
+			err = -EBUSY;
+		raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
 	}
 
+	if (err)
+		cscfg_config_desc_put(config_desc);
+
 	return err;
 }
 EXPORT_SYMBOL_GPL(cscfg_csdev_enable_active_config);
Signature · 1 line
2.52.0
#24 lore raw

Re: [PATCH v3 2/7] coresight: syscfg: Fail to enable a configuration not loaded on the device

Sashiko has reviewed this patch and found no issues.
Quoted 6 lines

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.

Quoted 7 lines

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

Sashiko has reviewed this patch and found no issues.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
#25 lore raw

PATCH v3 3/7 coresight: syscfg: Match feature capabilities separately from device class

In reply to Amir Ayupov

A feature loads on a device when the two share any match flag. That works for device classes, where a feature wants any one of them, but not for capabilities a device may or may not have: a feature that sets a class and a capability would still load on a device of that class without the capability.

Split the match flags into CS_CFG_MATCH_CLASS_MASK for device classes and CS_CFG_MATCH_CAP_MASK for capabilities. A feature now loads on a device that shares one of its classes and has all of its capabilities. Check this once in cscfg_load_feat_csdev(), which both the feature and the device registration paths call. No capability flags are defined yet, so matching is unchanged.

Assisted-by Devmate:Opus-5.5
---
 .../hwtracing/coresight/coresight-config.h    |  8 ++++
 .../hwtracing/coresight/coresight-syscfg.c    | 37 +++++++++++++------
 2 files changed, 34 insertions(+), 11 deletions(-)
drivers/hwtracing/coresight/coresight-config.h +8 -0
index ae6295e308131..f04e73b91d9a6 100644
@@ -7,6 +7,7 @@
 #ifndef _CORESIGHT_CORESIGHT_CONFIG_H
 #define _CORESIGHT_CORESIGHT_CONFIG_H
 
+#include <linux/bits.h>
 #include <linux/cleanup.h>
 #include <linux/coresight.h>
 #include <linux/types.h>
@@ -30,6 +31,13 @@
  */
 #define CS_CFG_MATCH_CLASS_SRC_ALL	0x0001	/* match any source */
 #define CS_CFG_MATCH_CLASS_SRC_ETM4	0x0002	/* match any ETMv4 device */
+#define CS_CFG_MATCH_CLASS_MASK		GENMASK_U32(7, 0)
+
+/*
+ * flags defining device capabilities a feature can require. A feature loads on
+ * a device that matches one of its classes and has all of its capabilities.
+ */
+#define CS_CFG_MATCH_CAP_MASK		GENMASK_U32(15, 8)
 
 /* flags defining device instance matching - used in config match desc data. */
 #define CS_CFG_MATCH_INST_ANY		0x80000000 /* any instance of a class */
drivers/hwtracing/coresight/coresight-syscfg.c +26 -11
index a816c22c87bc8..3ee104e94a4cd 100644
@@ -171,8 +171,22 @@ cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc
 	return feat_csdev;
 }
 
-/* load one feature into one coresight device */
+static bool cscfg_match_feat_csdev(u32 feat_flags, u32 csdev_flags)
+{
+	/* The device must be in one of the feature's classes */
+	if (!(feat_flags & csdev_flags & CS_CFG_MATCH_CLASS_MASK))
+		return false;
+
+	/* The device must have every capability the feature requires */
+	if (feat_flags & ~csdev_flags & CS_CFG_MATCH_CAP_MASK)
+		return false;
+
+	return true;
+}
+
+/* Load the feature into the device if it matches, otherwise skip it. */
 static int cscfg_load_feat_csdev(struct coresight_device *csdev,
+				 u32 match_flags,
 				 struct cscfg_feature_desc *feat_desc,
 				 struct cscfg_csdev_feat_ops *ops)
 {
@@ -183,6 +197,9 @@ static int cscfg_load_feat_csdev(struct coresight_device *csdev,
 	if (!ops->load_feat)
 		return -EINVAL;
 
+	if (!cscfg_match_feat_csdev(feat_desc->match_flags, match_flags))
+		return 0;
+
 	feat_csdev = cscfg_alloc_csdev_feat(csdev, feat_desc);
 	if (!feat_csdev)
 		return -ENOMEM;
@@ -212,11 +229,11 @@ static int cscfg_add_feat_to_csdevs(struct cscfg_feature_desc *feat_desc)
 	int err;
 
 	list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
-		if (csdev_item->match_flags & feat_desc->match_flags) {
-			err = cscfg_load_feat_csdev(csdev_item->csdev, feat_desc, &csdev_item->ops);
-			if (err)
-				return err;
-		}
+		err = cscfg_load_feat_csdev(csdev_item->csdev,
+					    csdev_item->match_flags, feat_desc,
+					    &csdev_item->ops);
+		if (err)
+			return err;
 	}
 	return 0;
 }
@@ -739,11 +756,9 @@ static int cscfg_add_feats_csdev(struct coresight_device *csdev,
 		return -EINVAL;
 
 	list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
-		if (feat_desc->match_flags & match_flags) {
-			err = cscfg_load_feat_csdev(csdev, feat_desc, ops);
-			if (err)
-				break;
-		}
+		err = cscfg_load_feat_csdev(csdev, match_flags, feat_desc, ops);
+		if (err)
+			break;
 	}
 	return err;
 }
Signature · 1 line
2.52.0
#26 lore raw

Re: [PATCH v3 3/7] coresight: syscfg: Match feature capabilities separately from device class

Sashiko has reviewed this patch and found no issues.
Quoted 13 lines

A feature loads on a device when the two share any match flag. That works for device classes, where a feature wants any one of them, but not for capabilities a device may or may not have: a feature that sets a class and a capability would still load on a device of that class without the capability.

Split the match flags into CS_CFG_MATCH_CLASS_MASK for device classes and CS_CFG_MATCH_CAP_MASK for capabilities. A feature now loads on a device that shares one of its classes and has all of its capabilities. Check this once in cscfg_load_feat_csdev(), which both the feature and the device registration paths call. No capability flags are defined yet, so matching is unchanged.

Quoted 2 lines
Assisted-by Devmate:Opus-5.5

Sashiko has reviewed this patch and found no issues.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
#27 lore raw

PATCH v3 4/7 coresight: syscfg: Remove unused CS_CFG_MATCH_INST_ANY

In reply to Amir Ayupov

CS_CFG_MATCH_INST_ANY has been defined since the system configuration was introduced but is not used by any configuration, feature or device. Remove it.

Assisted-by Devmate:Opus-5.5
---
 drivers/hwtracing/coresight/coresight-config.h | 3 ---
 1 file changed, 3 deletions(-)
drivers/hwtracing/coresight/coresight-config.h +0 -3
index f04e73b91d9a6..220bc54f8e5e1 100644
@@ -39,9 +39,6 @@
  */
 #define CS_CFG_MATCH_CAP_MASK		GENMASK_U32(15, 8)
 
-/* flags defining device instance matching - used in config match desc data. */
-#define CS_CFG_MATCH_INST_ANY		0x80000000 /* any instance of a class */
-
 /*
  * Limit number of presets in a configuration
  * This is related to the number of bits (4) we use to select the preset on
Signature · 1 line
2.52.0
#28 lore raw

Re: [PATCH v3 4/7] coresight: syscfg: Remove unused CS_CFG_MATCH_INST_ANY

Sashiko has reviewed this patch and found no issues.
Quoted 7 lines

CS_CFG_MATCH_INST_ANY has been defined since the system configuration was introduced but is not used by any configuration, feature or device. Remove it.

Assisted-by Devmate:Opus-5.5

Sashiko has reviewed this patch and found no issues.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=4
#29 lore raw

PATCH v3 5/7 perf: arm_pmuv3: Add pmuv3_event_implemented()

In reply to Amir Ayupov

Drivers outside the PMU driver may need to know whether the local CPU's PMU implements a common event before relying on it, for example a trace unit driver checking that the PMU counts its external outputs as TRCEXTOUTn.

Add pmuv3_event_implemented(), which reads PMCEID0/1 on the calling CPU:
events 0x0000-0x003f are reported in bits [31:0], and the common events from ARMV8_PMUV3_EXT_COMMON_EVENT_BASE in bits [63:32] from PMUv3p1. Move ARMV8_PMUV3_EXT_COMMON_EVENT_BASE next to the event numbers in arm_pmuv3.h so it is available without CONFIG_ARM_PMU.

Assisted-by Devmate:Opus-5.5
---
 include/linux/perf/arm_pmu.h   |  1 -
 include/linux/perf/arm_pmuv3.h | 22 ++++++++++++++++++++++
 2 files changed, 22 insertions(+), 1 deletion(-)
include/linux/perf/arm_pmu.h +0 -1
index 02d2c7f45b527..792283d29d7b5 100644
@@ -124,7 +124,6 @@ struct arm_pmu {
 	u64		reg_brbidr;
 #define ARMV8_PMUV3_MAX_COMMON_EVENTS		0x40
 	DECLARE_BITMAP(pmceid_bitmap, ARMV8_PMUV3_MAX_COMMON_EVENTS);
-#define ARMV8_PMUV3_EXT_COMMON_EVENT_BASE	0x4000
 	DECLARE_BITMAP(pmceid_ext_bitmap, ARMV8_PMUV3_MAX_COMMON_EVENTS);
 
 	/* Only to be used by ACPI probing code */
include/linux/perf/arm_pmuv3.h +22 -0
index d698efba28a27..965c40b28dd77 100644
@@ -78,6 +78,9 @@
 #define ARMV8_PMUV3_PERFCTR_STALL_SLOT_FRONTEND			0x003E
 #define ARMV8_PMUV3_PERFCTR_STALL_SLOT				0x003F
 
+/* Base of the common events reported in PMCEID{0,1}[63:32] from PMUv3p1 */
+#define ARMV8_PMUV3_EXT_COMMON_EVENT_BASE			0x4000
+
 /* Statistical profiling extension microarchitectural events */
 #define ARMV8_SPE_PERFCTR_SAMPLE_POP				0x4000
 #define ARMV8_SPE_PERFCTR_SAMPLE_FEED				0x4001
@@ -315,4 +318,23 @@
 
 #include <asm/arm_pmuv3.h>
 
+/*
+ * Whether this CPU's PMU implements a common event, as reported by
+ * PMCEID{0,1}: events 0x0000-0x003f in bits [31:0], and from PMUv3p1 events
+ * 0x4000-0x403f in bits [63:32], which read as zero before PMUv3p1.
+ * Must run on the CPU whose PMU is queried.
+ */
+static inline bool pmuv3_event_implemented(u16 event)
+{
+	bool ext = event >= ARMV8_PMUV3_EXT_COMMON_EVENT_BASE;
+	u16 id = ext ? event - ARMV8_PMUV3_EXT_COMMON_EVENT_BASE : event;
+	u64 pmceid;
+
+	if (id >= 64 || !pmuv3_implemented(read_pmuver()))
+		return false;
+
+	pmceid = id < 32 ? read_pmceid0() : read_pmceid1();
+	return pmceid & BIT_ULL(id % 32 + (ext ? 32 : 0));
+}
+
 #endif
Signature · 1 line
2.52.0
#30 lore raw

Re: [PATCH v3 5/7] perf: arm_pmuv3: Add pmuv3_event_implemented()

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] perf: arm_pmuv3: circular header inclusion in pmuv3_event_implemented() --

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] perf: arm_pmuv3: circular header inclusion in pmuv3_event_implemented() --

commit fe846ad9d18510169af8401fb7c59990c15ea903
Author: Amir Ayupov <[email protected]>

perf: arm_pmuv3: Add pmuv3_event_implemented()

This commit adds pmuv3_event_implemented() to include/linux/perf/arm_pmuv3.h to allow drivers outside the PMU driver to check whether the local CPU's PMU implements a common event via PMCEID0/1, and moves ARMV8_PMUV3_EXT_COMMON_EVENT_BASE into include/linux/perf/arm_pmuv3.h.

Quoted 4 lines
include/linux/perf/arm_pmuv3.h +0 -0
index d698efba28a27..965c40b28dd77 100644

[ ... ]

Quoted 12 lines
include/linux/perf/arm_pmuv3.h +8 -0
@@ -315,4 +318,23 @@
 
 #include <asm/arm_pmuv3.h>
 
+/*
+ * Whether this CPU's PMU implements a common event, as reported by
+ * PMCEID{0,1}: events 0x0000-0x003f in bits [31:0], and from PMUv3p1 events
+ * 0x4000-0x403f in bits [63:32], which read as zero before PMUv3p1.
+ * Must run on the CPU whose PMU is queried.
+ */
+static inline bool pmuv3_event_implemented(u16 event)
+{

include/linux/perf/arm_pmuv3.h line 338

Quoted 10 lines
include/linux/perf/arm_pmuv3.h +10 -0
+	bool ext = event >= ARMV8_PMUV3_EXT_COMMON_EVENT_BASE;
+	u16 id = ext ? event - ARMV8_PMUV3_EXT_COMMON_EVENT_BASE : event;
+	u64 pmceid;
+
+	if (id >= 64 || !pmuv3_implemented(read_pmuver()))
+		return false;
+
+	pmceid = id < 32 ? read_pmceid0() : read_pmceid1();
+	return pmceid & BIT_ULL(id % 32 + (ext ? 32 : 0));
+}

[Severity: Low]
Does defining pmuv3_event_implemented() here break arm64 builds due to a circular header dependency when a translation unit includes <asm/arm_pmuv3.h> before <asm/kvm_host.h> or <linux/perf/arm_pmuv3.h>?

For example, arch/arm64/kernel/cpufeature.c includes <asm/arm_pmuv3.h> first:

    #include <asm/arm_pmuv3.h>
    #include <asm/cpu.h>
    #include <asm/cpufeature.h>
    #include <asm/cpu_ops.h>
    #include <asm/fpsimd.h>
    #include <asm/hwcap.h>
    #include <asm/insn.h>
    #include <asm/kvm_host.h>

In arch/arm64/include/asm/arm_pmuv3.h, the header guard __ASM_PMUV3_H is defined and <asm/kvm_host.h> is included at the top before read_pmuver(), read_pmceid0(), read_pmceid1(), and pmuv3_implemented() are defined:

    #ifndef __ASM_PMUV3_H
    #define __ASM_PMUV3_H

    #include <asm/kvm_host.h>

That triggers the inclusion chain:

    arch/arm64/include/asm/arm_pmuv3.h
      -> arch/arm64/include/asm/kvm_host.h
        -> include/kvm/arm_pmu.h
          -> include/linux/perf/arm_pmuv3.h

When include/linux/perf/arm_pmuv3.h reaches #include <asm/arm_pmuv3.h>, it is skipped because __ASM_PMUV3_H is already defined, so pmuv3_event_implemented() is compiled before pmuv3_implemented(), read_pmuver(), read_pmceid0(), and read_pmceid1() have been declared.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=5
#31 lore raw

Re: [PATCH v3 5/7] perf: arm_pmuv3: Add pmuv3_event_implemented()

In reply to Amir Ayupov
kernel test robot noticed the following build errors:

Hi Amir,

kernel test robot noticed the following build errors:

[auto build test ERROR on 343cfcbb3ecfdb80aa576a428cfa3b65ad783842]

url:    https://github.com/intel-lab-lkp/linux/commits/Amir-Ayupov/coresight-etm4x-Fix-event-count-decoding/20261024-233901
base:   343cfcbb3ecfdb80aa576a428cfa3b65ad783842
patch link:    https://lore.kernel.org/r/cd3e622681f7254216b0488f09d2cb2d91a2d8ca.1792907333.git.aaupov%40fb.com
patch subject: [PATCH v3 5/7] perf: arm_pmuv3: Add pmuv3_event_implemented()
config: arm64-allnoconfig (https://download.01.org/0day-ci/archive/20261026/[email protected]/config)
compiler: aarch64-linux-gcc (GCC) 16.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261026/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

In file included from include/kvm/arm_pmu.h:11,

                    from arch/arm64/include/asm/kvm_host.h:38,
                    from arch/arm64/include/asm/arm_pmuv3.h:9,
                    from arch/arm64/kernel/cpufeature.c:80:
   include/linux/perf/arm_pmuv3.h: In function 'pmuv3_event_implemented':
>> include/linux/perf/arm_pmuv3.h:333:26: error: implicit declaration of function 'pmuv3_implemented'; did you mean 'pmuv3_event_implemented'? [-Wimplicit-function-declaration]
     333 |         if (id >= 64 || !pmuv3_implemented(read_pmuver()))
         |                          ^~~~~~~~~~~~~~~~~
         |                          pmuv3_event_implemented
>> include/linux/perf/arm_pmuv3.h:333:44: error: implicit declaration of function 'read_pmuver' [-Wimplicit-function-declaration]
     333 |         if (id >= 64 || !pmuv3_implemented(read_pmuver()))
         |                                            ^~~~~~~~~~~
>> include/linux/perf/arm_pmuv3.h:336:28: error: implicit declaration of function 'read_pmceid0' [-Wimplicit-function-declaration]
     336 |         pmceid = id < 32 ? read_pmceid0() : read_pmceid1();
         |                            ^~~~~~~~~~~~
>> include/linux/perf/arm_pmuv3.h:336:45: error: implicit declaration of function 'read_pmceid1' [-Wimplicit-function-declaration]
     336 |         pmceid = id < 32 ? read_pmceid0() : read_pmceid1();
         |                                             ^~~~~~~~~~~~
   arch/arm64/include/asm/arm_pmuv3.h: At top level:
>> arch/arm64/include/asm/arm_pmuv3.h:49:19: error: conflicting types for 'read_pmuver'; have 'u32(void)' {aka 'unsigned int(void)'}
      49 | static inline u32 read_pmuver(void)
         |                   ^~~~~~~~~~~
   include/linux/perf/arm_pmuv3.h:333:44: note: previous implicit declaration of 'read_pmuver' with type 'int()'
     333 |         if (id >= 64 || !pmuv3_implemented(read_pmuver()))
         |                                            ^~~~~~~~~~~
>> arch/arm64/include/asm/arm_pmuv3.h:160:19: error: conflicting types for 'read_pmceid0'; have 'u64(void)' {aka 'long long unsigned int(void)'}
     160 | static inline u64 read_pmceid0(void)
         |                   ^~~~~~~~~~~~
   include/linux/perf/arm_pmuv3.h:336:28: note: previous implicit declaration of 'read_pmceid0' with type 'int()'
     336 |         pmceid = id < 32 ? read_pmceid0() : read_pmceid1();
         |                            ^~~~~~~~~~~~
>> arch/arm64/include/asm/arm_pmuv3.h:165:19: error: conflicting types for 'read_pmceid1'; have 'u64(void)' {aka 'long long unsigned int(void)'}
     165 | static inline u64 read_pmceid1(void)
         |                   ^~~~~~~~~~~~
   include/linux/perf/arm_pmuv3.h:336:45: note: previous implicit declaration of 'read_pmceid1' with type 'int()'
     336 |         pmceid = id < 32 ? read_pmceid0() : read_pmceid1();
         |                                             ^~~~~~~~~~~~
>> arch/arm64/include/asm/arm_pmuv3.h:170:20: error: conflicting types for 'pmuv3_implemented'; have 'bool(int)' {aka '_Bool(int)'}
     170 | static inline bool pmuv3_implemented(int pmuver)
         |                    ^~~~~~~~~~~~~~~~~
   include/linux/perf/arm_pmuv3.h:333:26: note: previous implicit declaration of 'pmuv3_implemented' with type 'int()'
     333 |         if (id >= 64 || !pmuv3_implemented(read_pmuver()))
         |                          ^~~~~~~~~~~~~~~~~

vim +333 include/linux/perf/arm_pmuv3.h

320
321 /*
322 * Whether this CPU's PMU implements a common event, as reported by
323 * PMCEID{0,1}: events 0x0000-0x003f in bits [31:0], and from PMUv3p1 events
324 * 0x4000-0x403f in bits [63:32], which read as zero before PMUv3p1.
325 * Must run on the CPU whose PMU is queried.
326 */
327 static inline bool pmuv3_event_implemented(u16 event)
328 {
329 bool ext = event >= ARMV8_PMUV3_EXT_COMMON_EVENT_BASE;
330 u16 id = ext ? event - ARMV8_PMUV3_EXT_COMMON_EVENT_BASE : event;
331 u64 pmceid;
332

 > 333		if (id >= 64 || !pmuv3_implemented(read_pmuver()))
   334			return false;
   335	
 > 336		pmceid = id < 32 ? read_pmceid0() : read_pmceid1();

337 return pmceid & BIT_ULL(id % 32 + (ext ? 32 : 0));
338 }
339

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

#32 lore raw

Re: [PATCH v3 5/7] perf: arm_pmuv3: Add pmuv3_event_implemented()

In reply to Amir Ayupov
kernel test robot noticed the following build errors:

Hi Amir,

kernel test robot noticed the following build errors:

[auto build test ERROR on 343cfcbb3ecfdb80aa576a428cfa3b65ad783842]

url:    https://github.com/intel-lab-lkp/linux/commits/Amir-Ayupov/coresight-etm4x-Fix-event-count-decoding/20261024-233901
base:   343cfcbb3ecfdb80aa576a428cfa3b65ad783842
patch link:    https://lore.kernel.org/r/cd3e622681f7254216b0488f09d2cb2d91a2d8ca.1792907333.git.aaupov%40fb.com
patch subject: [PATCH v3 5/7] perf: arm_pmuv3: Add pmuv3_event_implemented()
config: arm64-randconfig-1003-20261026 (https://download.01.org/0day-ci/archive/20261026/[email protected]/config)
compiler: aarch64-linux-gcc (GCC) 8.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261026/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

In file included from include/kvm/arm_pmu.h:11,

                    from arch/arm64/include/asm/kvm_host.h:38,
                    from arch/arm64/include/asm/arm_pmuv3.h:9,
                    from arch/arm64/kernel/cpufeature.c:80:
   include/linux/perf/arm_pmuv3.h: In function 'pmuv3_event_implemented':
   include/linux/perf/arm_pmuv3.h:333:19: error: implicit declaration of function 'pmuv3_implemented'; did you mean 'pmuv3_event_implemented'? [-Werror=implicit-function-declaration]
     if (id >= 64 || !pmuv3_implemented(read_pmuver()))
                      ^~~~~~~~~~~~~~~~~
                      pmuv3_event_implemented
   include/linux/perf/arm_pmuv3.h:333:37: error: implicit declaration of function 'read_pmuver'; did you mean 'read_tcr'? [-Werror=implicit-function-declaration]
     if (id >= 64 || !pmuv3_implemented(read_pmuver()))
                                        ^~~~~~~~~~~
                                        read_tcr
   include/linux/perf/arm_pmuv3.h:336:21: error: implicit declaration of function 'read_pmceid0'; did you mean 'read_cpuid'? [-Werror=implicit-function-declaration]
     pmceid = id < 32 ? read_pmceid0() : read_pmceid1();
                        ^~~~~~~~~~~~
                        read_cpuid
   include/linux/perf/arm_pmuv3.h:336:38: error: implicit declaration of function 'read_pmceid1'; did you mean 'read_cpuid'? [-Werror=implicit-function-declaration]
     pmceid = id < 32 ? read_pmceid0() : read_pmceid1();
                                         ^~~~~~~~~~~~
                                         read_cpuid
   In file included from arch/arm64/kernel/cpufeature.c:80:
   arch/arm64/include/asm/arm_pmuv3.h: At top level:
>> arch/arm64/include/asm/arm_pmuv3.h:49:19: error: conflicting types for 'read_pmuver'
    static inline u32 read_pmuver(void)
                      ^~~~~~~~~~~
   In file included from include/kvm/arm_pmu.h:11,
                    from arch/arm64/include/asm/kvm_host.h:38,
                    from arch/arm64/include/asm/arm_pmuv3.h:9,
                    from arch/arm64/kernel/cpufeature.c:80:
   include/linux/perf/arm_pmuv3.h:333:37: note: previous implicit declaration of 'read_pmuver' was here
     if (id >= 64 || !pmuv3_implemented(read_pmuver()))
                                        ^~~~~~~~~~~
   In file included from arch/arm64/kernel/cpufeature.c:80:
>> arch/arm64/include/asm/arm_pmuv3.h:160:19: error: conflicting types for 'read_pmceid0'
    static inline u64 read_pmceid0(void)
                      ^~~~~~~~~~~~
   In file included from include/kvm/arm_pmu.h:11,
                    from arch/arm64/include/asm/kvm_host.h:38,
                    from arch/arm64/include/asm/arm_pmuv3.h:9,
                    from arch/arm64/kernel/cpufeature.c:80:
   include/linux/perf/arm_pmuv3.h:336:21: note: previous implicit declaration of 'read_pmceid0' was here
     pmceid = id < 32 ? read_pmceid0() : read_pmceid1();
                        ^~~~~~~~~~~~
   In file included from arch/arm64/kernel/cpufeature.c:80:
>> arch/arm64/include/asm/arm_pmuv3.h:165:19: error: conflicting types for 'read_pmceid1'
    static inline u64 read_pmceid1(void)
                      ^~~~~~~~~~~~
   In file included from include/kvm/arm_pmu.h:11,
                    from arch/arm64/include/asm/kvm_host.h:38,
                    from arch/arm64/include/asm/arm_pmuv3.h:9,
                    from arch/arm64/kernel/cpufeature.c:80:
   include/linux/perf/arm_pmuv3.h:336:38: note: previous implicit declaration of 'read_pmceid1' was here
     pmceid = id < 32 ? read_pmceid0() : read_pmceid1();
                                         ^~~~~~~~~~~~
   In file included from arch/arm64/kernel/cpufeature.c:80:
>> arch/arm64/include/asm/arm_pmuv3.h:170:20: error: conflicting types for 'pmuv3_implemented'
    static inline bool pmuv3_implemented(int pmuver)
                       ^~~~~~~~~~~~~~~~~
   In file included from include/kvm/arm_pmu.h:11,
                    from arch/arm64/include/asm/kvm_host.h:38,
                    from arch/arm64/include/asm/arm_pmuv3.h:9,
                    from arch/arm64/kernel/cpufeature.c:80:
   include/linux/perf/arm_pmuv3.h:333:19: note: previous implicit declaration of 'pmuv3_implemented' was here
     if (id >= 64 || !pmuv3_implemented(read_pmuver()))
                      ^~~~~~~~~~~~~~~~~
   arch/arm64/kernel/cpufeature.c:3364:21: warning: initialized field overwritten [-Woverride-init]
     HWCAP_CAP_MATCH_ID(has_sve_feature, ID_AA64ISAR2_EL1, LUT, LUT6, CAP_HWCAP, KERNEL_HWCAP_SVE_LUT6),
                        ^~~~~~~~~~~~~~~
   arch/arm64/kernel/cpufeature.c:3273:14: note: in definition of macro 'HWCAP_CAP_MATCH_ID'
      .matches = match,      \
                 ^~~~~
   arch/arm64/kernel/cpufeature.c:3364:21: note: (near initialization for 'arm64_elf_hwcaps[44].matches')
     HWCAP_CAP_MATCH_ID(has_sve_feature, ID_AA64ISAR2_EL1, LUT, LUT6, CAP_HWCAP, KERNEL_HWCAP_SVE_LUT6),
                        ^~~~~~~~~~~~~~~
   arch/arm64/kernel/cpufeature.c:3273:14: note: in definition of macro 'HWCAP_CAP_MATCH_ID'
      .matches = match,      \
                 ^~~~~
   arch/arm64/kernel/cpufeature.c:3366:21: warning: initialized field overwritten [-Woverride-init]
     HWCAP_CAP_MATCH_ID(has_sve_feature, ID_AA64ZFR0_EL1, SVEver, SVE2p3, CAP_HWCAP, KERNEL_HWCAP_SVE2P3),
                        ^~~~~~~~~~~~~~~
   arch/arm64/kernel/cpufeature.c:3273:14: note: in definition of macro 'HWCAP_CAP_MATCH_ID'
      .matches = match,      \
                 ^~~~~
   arch/arm64/kernel/cpufeature.c:3366:21: note: (near initialization for 'arm64_elf_hwcaps[46].matches')
     HWCAP_CAP_MATCH_ID(has_sve_feature, ID_AA64ZFR0_EL1, SVEver, SVE2p3, CAP_HWCAP, KERNEL_HWCAP_SVE2P3),
                        ^~~~~~~~~~~~~~~
   arch/arm64/kernel/cpufeature.c:3273:14: note: in definition of macro 'HWCAP_CAP_MATCH_ID'
      .matches = match,      \
                 ^~~~~
   arch/arm64/kernel/cpufeature.c:3367:21: warning: initialized field overwritten [-Woverride-init]
     HWCAP_CAP_MATCH_ID(has_sve_feature, ID_AA64ZFR0_EL1, SVEver, SVE2p2, CAP_HWCAP, KERNEL_HWCAP_SVE2P2),
                        ^~~~~~~~~~~~~~~
   arch/arm64/kernel/cpufeature.c:3273:14: note: in definition of macro 'HWCAP_CAP_MATCH_ID'
      .matches = match,      \
                 ^~~~~
   arch/arm64/kernel/cpufeature.c:3367:21: note: (near initialization for 'arm64_elf_hwcaps[47].matches')
     HWCAP_CAP_MATCH_ID(has_sve_feature, ID_AA64ZFR0_EL1, SVEver, SVE2p2, CAP_HWCAP, KERNEL_HWCAP_SVE2P2),
                        ^~~~~~~~~~~~~~~
   arch/arm64/kernel/cpufeature.c:3273:14: note: in definition of macro 'HWCAP_CAP_MATCH_ID'
      .matches = match,      \
                 ^~~~~
   arch/arm64/kernel/cpufeature.c:3368:21: warning: initialized field overwritten [-Woverride-init]
     HWCAP_CAP_MATCH_ID(has_sve_feature, ID_AA64ZFR0_EL1, SVEver, SVE2p1, CAP_HWCAP, KERNEL_HWCAP_SVE2P1),
                        ^~~~~~~~~~~~~~~
   arch/arm64/kernel/cpufeature.c:3273:14: note: in definition of macro 'HWCAP_CAP_MATCH_ID'
      .matches = match,      \
                 ^~~~~
   arch/arm64/kernel/cpufeature.c:3368:21: note: (near initialization for 'arm64_elf_hwcaps[48].matches')
     HWCAP_CAP_MATCH_ID(has_sve_feature, ID_AA64ZFR0_EL1, SVEver, SVE2p1, CAP_HWCAP, KERNEL_HWCAP_SVE2P1),
                        ^~~~~~~~~~~~~~~
   arch/arm64/kernel/cpufeature.c:3273:14: note: in definition of macro 'HWCAP_CAP_MATCH_ID'
      .matches = match,      \
                 ^~~~~
   arch/arm64/kernel/cpufeature.c:3369:21: warning: initialized field overwritten [-Woverride-init]
     HWCAP_CAP_MATCH_ID(has_sve_feature, ID_AA64ZFR0_EL1, SVEver, SVE2, CAP_HWCAP, KERNEL_HWCAP_SVE2),
                        ^~~~~~~~~~~~~~~
   arch/arm64/kernel/cpufeature.c:3273:14: note: in definition of macro 'HWCAP_CAP_MATCH_ID'
      .matches = match,      \
                 ^~~~~
   arch/arm64/kernel/cpufeature.c:3369:21: note: (near initialization for 'arm64_elf_hwcaps[49].matches')
     HWCAP_CAP_MATCH_ID(has_sve_feature, ID_AA64ZFR0_EL1, SVEver, SVE2, CAP_HWCAP, KERNEL_HWCAP_SVE2),
                        ^~~~~~~~~~~~~~~
   arch/arm64/kernel/cpufeature.c:3273:14: note: in definition of macro 'HWCAP_CAP_MATCH_ID'
      .matches = match,      \
                 ^~~~~
   arch/arm64/kernel/cpufeature.c:3370:21: warning: initialized field overwritten [-Woverride-init]
     HWCAP_CAP_MATCH_ID(has_sve_feature, ID_AA64ZFR0_EL1, AES, IMP, CAP_HWCAP, KERNEL_HWCAP_SVEAES),
                        ^~~~~~~~~~~~~~~
   arch/arm64/kernel/cpufeature.c:3273:14: note: in definition of macro 'HWCAP_CAP_MATCH_ID'
      .matches = match,      \
                 ^~~~~
   arch/arm64/kernel/cpufeature.c:3370:21: note: (near initialization for 'arm64_elf_hwcaps[50].matches')
     HWCAP_CAP_MATCH_ID(has_sve_feature, ID_AA64ZFR0_EL1, AES, IMP, CAP_HWCAP, KERNEL_HWCAP_SVEAES),
                        ^~~~~~~~~~~~~~~
   arch/arm64/kernel/cpufeature.c:3273:14: note: in definition of macro 'HWCAP_CAP_MATCH_ID'
      .matches = match,      \
                 ^~~~~
   arch/arm64/kernel/cpufeature.c:3371:21: warning: initialized field overwritten [-Woverride-init]
     HWCAP_CAP_MATCH_ID(has_sve_feature, ID_AA64ZFR0_EL1, AES, PMULL128, CAP_HWCAP, KERNEL_HWCAP_SVEPMULL),
                        ^~~~~~~~~~~~~~~
   arch/arm64/kernel/cpufeature.c:3273:14: note: in definition of macro 'HWCAP_CAP_MATCH_ID'
      .matches = match,      \
                 ^~~~~
   arch/arm64/kernel/cpufeature.c:3371:21: note: (near initialization for 'arm64_elf_hwcaps[51].matches')
     HWCAP_CAP_MATCH_ID(has_sve_feature, ID_AA64ZFR0_EL1, AES, PMULL128, CAP_HWCAP, KERNEL_HWCAP_SVEPMULL),
                        ^~~~~~~~~~~~~~~
   arch/arm64/kernel/cpufeature.c:3273:14: note: in definition of macro 'HWCAP_CAP_MATCH_ID'
      .matches = match,      \
                 ^~~~~
   arch/arm64/kernel/cpufeature.c:3372:21: warning: initialized field overwritten [-Woverride-init]
     HWCAP_CAP_MATCH_ID(has_sve_feature, ID_AA64ZFR0_EL1, AES, AES2, CAP_HWCAP, KERNEL_HWCAP_SVE_AES2),
                        ^~~~~~~~~~~~~~~
   arch/arm64/kernel/cpufeature.c:3273:14: note: in definition of macro 'HWCAP_CAP_MATCH_ID'
      .matches = match,      \
                 ^~~~~

arch/arm64/kernel/cpufeature.c:3372:21: note: (near initialization for 'arm64_elf_hwcaps[52].matches')

vim +/read_pmuver +49 arch/arm64/include/asm/arm_pmuv3.h

df29ddf4f04b00 Marc Zyngier      2023-03-17   48  
df29ddf4f04b00 Marc Zyngier      2023-03-17  @49  static inline u32 read_pmuver(void)
df29ddf4f04b00 Marc Zyngier      2023-03-17   50  {
df29ddf4f04b00 Marc Zyngier      2023-03-17   51  	u64 dfr0 = read_sysreg(id_aa64dfr0_el1);
df29ddf4f04b00 Marc Zyngier      2023-03-17   52  
df29ddf4f04b00 Marc Zyngier      2023-03-17   53  	return cpuid_feature_extract_unsigned_field(dfr0,
df29ddf4f04b00 Marc Zyngier      2023-03-17   54  			ID_AA64DFR0_EL1_PMUVer_SHIFT);
df29ddf4f04b00 Marc Zyngier      2023-03-17   55  }
df29ddf4f04b00 Marc Zyngier      2023-03-17   56  
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31   57) static inline bool pmuv3_has_icntr(void)
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31   58) {
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31   59) 	u64 dfr1 = read_sysreg(id_aa64dfr1_el1);
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31   60) 
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31   61) 	return !!cpuid_feature_extract_unsigned_field(dfr1,
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31   62) 			ID_AA64DFR1_EL1_PMICNTR_SHIFT);
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31   63) }
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31   64) 
403edfa436286b Ilkka Koskinen    2023-11-02   65  static inline void write_pmcr(u64 val)
df29ddf4f04b00 Marc Zyngier      2023-03-17   66  {
df29ddf4f04b00 Marc Zyngier      2023-03-17   67  	write_sysreg(val, pmcr_el0);
df29ddf4f04b00 Marc Zyngier      2023-03-17   68  }
df29ddf4f04b00 Marc Zyngier      2023-03-17   69  
403edfa436286b Ilkka Koskinen    2023-11-02   70  static inline u64 read_pmcr(void)
df29ddf4f04b00 Marc Zyngier      2023-03-17   71  {
df29ddf4f04b00 Marc Zyngier      2023-03-17   72  	return read_sysreg(pmcr_el0);
df29ddf4f04b00 Marc Zyngier      2023-03-17   73  }
df29ddf4f04b00 Marc Zyngier      2023-03-17   74  
df29ddf4f04b00 Marc Zyngier      2023-03-17   75  static inline void write_pmselr(u32 val)
df29ddf4f04b00 Marc Zyngier      2023-03-17   76  {
df29ddf4f04b00 Marc Zyngier      2023-03-17   77  	write_sysreg(val, pmselr_el0);
df29ddf4f04b00 Marc Zyngier      2023-03-17   78  }
df29ddf4f04b00 Marc Zyngier      2023-03-17   79  
df29ddf4f04b00 Marc Zyngier      2023-03-17   80  static inline void write_pmccntr(u64 val)
df29ddf4f04b00 Marc Zyngier      2023-03-17   81  {
df29ddf4f04b00 Marc Zyngier      2023-03-17   82  	write_sysreg(val, pmccntr_el0);
df29ddf4f04b00 Marc Zyngier      2023-03-17   83  }
df29ddf4f04b00 Marc Zyngier      2023-03-17   84  
df29ddf4f04b00 Marc Zyngier      2023-03-17   85  static inline u64 read_pmccntr(void)
df29ddf4f04b00 Marc Zyngier      2023-03-17   86  {
df29ddf4f04b00 Marc Zyngier      2023-03-17   87  	return read_sysreg(pmccntr_el0);
df29ddf4f04b00 Marc Zyngier      2023-03-17   88  }
df29ddf4f04b00 Marc Zyngier      2023-03-17   89  
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31   90) static inline void write_pmicntr(u64 val)
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31   91) {
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31   92) 	write_sysreg_s(val, SYS_PMICNTR_EL0);
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31   93) }
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31   94) 
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31   95) static inline u64 read_pmicntr(void)
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31   96) {
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31   97) 	return read_sysreg_s(SYS_PMICNTR_EL0);
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31   98) }
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31   99) 
a4a6e2078d85a9 Rob Herring (Arm  2024-07-31  100) static inline void write_pmcntenset(u64 val)
df29ddf4f04b00 Marc Zyngier      2023-03-17  101  {
df29ddf4f04b00 Marc Zyngier      2023-03-17  102  	write_sysreg(val, pmcntenset_el0);
df29ddf4f04b00 Marc Zyngier      2023-03-17  103  }
df29ddf4f04b00 Marc Zyngier      2023-03-17  104  
a4a6e2078d85a9 Rob Herring (Arm  2024-07-31  105) static inline void write_pmcntenclr(u64 val)
df29ddf4f04b00 Marc Zyngier      2023-03-17  106  {
df29ddf4f04b00 Marc Zyngier      2023-03-17  107  	write_sysreg(val, pmcntenclr_el0);
df29ddf4f04b00 Marc Zyngier      2023-03-17  108  }
df29ddf4f04b00 Marc Zyngier      2023-03-17  109  
a4a6e2078d85a9 Rob Herring (Arm  2024-07-31  110) static inline void write_pmintenset(u64 val)
df29ddf4f04b00 Marc Zyngier      2023-03-17  111  {
df29ddf4f04b00 Marc Zyngier      2023-03-17  112  	write_sysreg(val, pmintenset_el1);
df29ddf4f04b00 Marc Zyngier      2023-03-17  113  }
df29ddf4f04b00 Marc Zyngier      2023-03-17  114  
a4a6e2078d85a9 Rob Herring (Arm  2024-07-31  115) static inline void write_pmintenclr(u64 val)
df29ddf4f04b00 Marc Zyngier      2023-03-17  116  {
df29ddf4f04b00 Marc Zyngier      2023-03-17  117  	write_sysreg(val, pmintenclr_el1);
df29ddf4f04b00 Marc Zyngier      2023-03-17  118  }
df29ddf4f04b00 Marc Zyngier      2023-03-17  119  
403edfa436286b Ilkka Koskinen    2023-11-02  120  static inline void write_pmccfiltr(u64 val)
df29ddf4f04b00 Marc Zyngier      2023-03-17  121  {
df29ddf4f04b00 Marc Zyngier      2023-03-17  122  	write_sysreg(val, pmccfiltr_el0);
df29ddf4f04b00 Marc Zyngier      2023-03-17  123  }
df29ddf4f04b00 Marc Zyngier      2023-03-17  124  
741ee5284551cf Rob Herring (Arm  2024-07-31  125) static inline u64 read_pmccfiltr(void)
741ee5284551cf Rob Herring (Arm  2024-07-31  126) {
741ee5284551cf Rob Herring (Arm  2024-07-31  127) 	return read_sysreg(pmccfiltr_el0);
741ee5284551cf Rob Herring (Arm  2024-07-31  128) }
741ee5284551cf Rob Herring (Arm  2024-07-31  129) 
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31  130) static inline void write_pmicfiltr(u64 val)
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31  131) {
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31  132) 	write_sysreg_s(val, SYS_PMICFILTR_EL0);
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31  133) }
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31  134) 
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31  135) static inline u64 read_pmicfiltr(void)
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31  136) {
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31  137) 	return read_sysreg_s(SYS_PMICFILTR_EL0);
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31  138) }
d8226d8cfbaf5e Rob Herring (Arm  2024-07-31  139) 
a4a6e2078d85a9 Rob Herring (Arm  2024-07-31  140) static inline void write_pmovsclr(u64 val)
df29ddf4f04b00 Marc Zyngier      2023-03-17  141  {
df29ddf4f04b00 Marc Zyngier      2023-03-17  142  	write_sysreg(val, pmovsclr_el0);
df29ddf4f04b00 Marc Zyngier      2023-03-17  143  }
df29ddf4f04b00 Marc Zyngier      2023-03-17  144  
a4a6e2078d85a9 Rob Herring (Arm  2024-07-31  145) static inline u64 read_pmovsclr(void)
df29ddf4f04b00 Marc Zyngier      2023-03-17  146  {
df29ddf4f04b00 Marc Zyngier      2023-03-17  147  	return read_sysreg(pmovsclr_el0);
df29ddf4f04b00 Marc Zyngier      2023-03-17  148  }
df29ddf4f04b00 Marc Zyngier      2023-03-17  149  
df29ddf4f04b00 Marc Zyngier      2023-03-17  150  static inline void write_pmuserenr(u32 val)
df29ddf4f04b00 Marc Zyngier      2023-03-17  151  {
df29ddf4f04b00 Marc Zyngier      2023-03-17  152  	write_sysreg(val, pmuserenr_el0);
df29ddf4f04b00 Marc Zyngier      2023-03-17  153  }
df29ddf4f04b00 Marc Zyngier      2023-03-17  154  
0bbff9ed81654d Rob Herring (Arm  2024-10-02  155) static inline void write_pmuacr(u64 val)
0bbff9ed81654d Rob Herring (Arm  2024-10-02  156) {
0bbff9ed81654d Rob Herring (Arm  2024-10-02  157) 	write_sysreg_s(val, SYS_PMUACR_EL1);
0bbff9ed81654d Rob Herring (Arm  2024-10-02  158) }
0bbff9ed81654d Rob Herring (Arm  2024-10-02  159) 
403edfa436286b Ilkka Koskinen    2023-11-02 @160  static inline u64 read_pmceid0(void)
df29ddf4f04b00 Marc Zyngier      2023-03-17  161  {
df29ddf4f04b00 Marc Zyngier      2023-03-17  162  	return read_sysreg(pmceid0_el0);
df29ddf4f04b00 Marc Zyngier      2023-03-17  163  }
df29ddf4f04b00 Marc Zyngier      2023-03-17  164  
403edfa436286b Ilkka Koskinen    2023-11-02 @165  static inline u64 read_pmceid1(void)
df29ddf4f04b00 Marc Zyngier      2023-03-17  166  {
df29ddf4f04b00 Marc Zyngier      2023-03-17  167  	return read_sysreg(pmceid1_el0);
df29ddf4f04b00 Marc Zyngier      2023-03-17  168  }
df29ddf4f04b00 Marc Zyngier      2023-03-17  169  
711432770f78e5 Zaid Al-Bassam    2023-03-17 @170  static inline bool pmuv3_implemented(int pmuver)
711432770f78e5 Zaid Al-Bassam    2023-03-17  171  {
711432770f78e5 Zaid Al-Bassam    2023-03-17  172  	return !(pmuver == ID_AA64DFR0_EL1_PMUVer_IMP_DEF ||
711432770f78e5 Zaid Al-Bassam    2023-03-17  173  		 pmuver == ID_AA64DFR0_EL1_PMUVer_NI);
711432770f78e5 Zaid Al-Bassam    2023-03-17  174  }
711432770f78e5 Zaid Al-Bassam    2023-03-17  175  

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

#33 lore raw

PATCH v3 6/7 coresight: etm4x: Report whether the PMU counts the external outputs

In reply to Amir Ayupov

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
---
 .../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(-)
drivers/hwtracing/coresight/coresight-config.h +2 -0
index 220bc54f8e5e1..4cf53230854d0 100644
@@ -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
drivers/hwtracing/coresight/coresight-etm4x-cfg.c +5 -1
index 52cb036bb04b9..9e4dc5950c13d 100644
@@ -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);
 }
drivers/hwtracing/coresight/coresight-etm4x-core.c +26 -0
index af017bd8a5477..cb5fbb0279b88 100644
@@ -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);
drivers/hwtracing/coresight/coresight-etm4x.h +3 -0
index 5417280cdb274..33994ad4b2641 100644
@@ -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.
  */
 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;
 };
 
 /**
drivers/hwtracing/coresight/coresight-syscfg-configfs.c +3 -0
index 2b40e556be872..7b3800138f625 100644
@@ -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;
 }
Signature · 1 line
2.52.0
#34 lore raw

Re: [PATCH v3 6/7] coresight: etm4x: Report whether the PMU counts the external outputs

Sashiko has reviewed this patch and found no issues.
Quoted 13 lines

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.

Quoted 7 lines

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

Sashiko has reviewed this patch and found no issues.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=6
#35 lore raw

PATCH v3 7/7 coresight: Add pmu_pulse/extout_pulse

In reply to Amir Ayupov

Add ETMv4 configuration 'pmu_pulse' with 'extout_pulse' feature which requires an ETE whose PMU counts its external outputs (CS_CFG_MATCH_CAP_TRCEXTOUT): event 1 selects the always-true resource and drives TRCEXTOUT1 PMU event which pulses on every cycle while the trace unit is enabled.

Assisted-by Devmate:Opus-5.5
---
 .../trace/coresight/coresight-config.rst      |  5 ++
 .../trace/coresight/coresight-perf.rst        | 15 +++++
 drivers/hwtracing/coresight/Makefile          |  1 +
 .../coresight/coresight-cfg-pmu-pulse.c       | 55 +++++++++++++++++++
 .../coresight/coresight-cfg-preload.c         |  2 +
 .../coresight/coresight-cfg-preload.h         |  2 +
 6 files changed, 80 insertions(+)
 create mode 100644 drivers/hwtracing/coresight/coresight-cfg-pmu-pulse.c
Documentation/trace/coresight/coresight-config.rst +5 -0
index 6d5ffa6f73471..3eed728bf0de1 100644
@@ -129,6 +129,11 @@ The following steps take place in the operation of a configuration.
 
 5) At the end of the perf session, the configuration will be disabled.
 
+The built-in 'pmu_pulse' configuration pulses ETM external output 1 for a PMU
+event to count. It only pulses while the ETM is enabled, so combined with AUX
+pause and resume the PMU event can time each trace window (see
+coresight-perf.rst).
+
 
 Viewing Configurations and Features
 ===================================
Documentation/trace/coresight/coresight-perf.rst +15 -0
index 0a77741a431ef..6770a455c6b59 100644
@@ -109,6 +109,21 @@ Example for triggering AUX pause and resume with PMU event::
         -e cycles/aux-action=pause,period=10000000/ \
         -e cycles/aux-action=resume,period=1050000/ -- sleep 1
 
+ETM-timed pause events
+~~~~~~~~~~~~~~~~~~~~~~
+
+The built-in ``pmu_pulse`` configuration pulses ETM external output 1 on every
+cycle of allowed trace, and a PMU event counting that output pauses trace after
+``N`` pulses, here 1000 cycles::
+
+  perf record -a -e cs_etm/pmu_pulse,aux-action=start-paused/u \
+    -e cycles/aux-action=resume,period=10000000/u \
+    -e trcextout1/aux-action=pause,period=1000/u \
+    -- sleep 1
+
+Each window is about ``N`` traced cycles plus the pause interrupt latency.
+The configuration only loads on an ETE whose PMU counts its external outputs.
+
 Perf test - Verify kernel and userspace perf CoreSight work
 -----------------------------------------------------------
 
drivers/hwtracing/coresight/Makefile +1 -0
index ab16d06783a57..568e797ac5a17 100644
@@ -28,6 +28,7 @@ obj-$(CONFIG_CORESIGHT) += coresight.o
 coresight-y := coresight-core.o  coresight-etm-perf.o coresight-platform.o \
 		coresight-sysfs.o coresight-syscfg.o coresight-config.o \
 		coresight-cfg-preload.o coresight-cfg-afdo.o coresight-cfg-pstop.o \
+		coresight-cfg-pmu-pulse.o \
 		coresight-syscfg-configfs.o coresight-trace-id.o
 obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o
 coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \
drivers/hwtracing/coresight/coresight-cfg-pmu-pulse.c new file +55 -0

55 lines not on this page · raw message

drivers/hwtracing/coresight/coresight-cfg-preload.c +2 -0
index 4980e68483c5b..a9a60a1c40845 100644
@@ -14,6 +14,7 @@ static struct cscfg_feature_desc *preload_feats[] = {
 #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
 	&strobe_etm4x,
 	&gen_etrig_etm4x,
+	&extout_pulse_etm4x,
 #endif
 	NULL
 };
@@ -22,6 +23,7 @@ static struct cscfg_config_desc *preload_cfgs[] = {
 #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
 	&afdo_etm4x,
 	&pstop_etm4x,
+	&pmu_pulse_etm4x,
 #endif
 	NULL
 };
drivers/hwtracing/coresight/coresight-cfg-preload.h +2 -0
index 291ba530a6a52..0058627f65ae5 100644
@@ -12,4 +12,6 @@ extern struct cscfg_feature_desc strobe_etm4x;
 extern struct cscfg_config_desc afdo_etm4x;
 extern struct cscfg_feature_desc gen_etrig_etm4x;
 extern struct cscfg_config_desc pstop_etm4x;
+extern struct cscfg_feature_desc extout_pulse_etm4x;
+extern struct cscfg_config_desc pmu_pulse_etm4x;
 #endif
Signature · 1 line
2.52.0
#36 lore raw

Re: [PATCH v3 7/7] coresight: Add pmu_pulse/extout_pulse

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] coresight: pmu_pulse loads on 1-event ETE lacking event 1 and TRCEXTOUT1 --

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] coresight: pmu_pulse loads on 1-event ETE lacking event 1 and TRCEXTOUT1 --

commit 75adf8bc69eef9902a1a675969ecaf268f815f11
Author: Amir Ayupov <[email protected]>

coresight: Add pmu_pulse/extout_pulse

This commit adds a built-in pmu_pulse configuration and extout_pulse feature for ETMv4/ETE trace units that program event 1 in TRCEVENTCTL0R to select the always-true resource and pulse external output 1 (TRCEXTOUT1) on every traced cycle.

Quoted 34 lines
drivers/hwtracing/coresight/coresight-cfg-pmu-pulse.c new file +28 -0
new file mode 100644
index 0000000000000..61472154dd02a
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Pulse ETM external output 1 on every traced cycle for a PMU event to count.
+ * Based on coresight-cfg-afdo.c
+ */
+
+#include "coresight-config.h"
+
+/* ETMv4 includes and features */
+#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
+#include "coresight-etm4x-cfg.h"
+
+/*
+ * extout_pulse feature: event 1 selects the always-true resource, so ETM
+ * external output 1 pulses on every cycle while the trace unit is enabled. A
+ * PMU event counting that output (TRCEXTOUT1), for example with
+ * aux-action=pause, then fires after as many traced cycles as its sample
+ * period. Event 0 is avoided because it is the trace unit trigger, and the
+ * TRBE driver treats a detected trigger as fatal.
+ */
+static struct cscfg_regval_desc extout_pulse_regs[] = {
+	/* event 1: resource selector 1 (always true), drives external output 1 */
+	{
+		.type = CS_CFG_REG_TYPE_STD | CS_CFG_REG_TYPE_VAL_MASK,
+		.offset = TRCEVENTCTL0R,
+		.val32 = 0x0100,
+		.mask32 = 0xff00,
+	},

drivers/hwtracing/coresight/coresight-cfg-pmu-pulse.c line 38

Quoted 10 lines
drivers/hwtracing/coresight/coresight-cfg-pmu-pulse.c new file +10 -0
+	/* end of regs */
+};
+
+struct cscfg_feature_desc extout_pulse_etm4x = {
+	.name = "extout_pulse",
+	.description = "Pulse external output 1 on every traced cycle.\n",
+	.match_flags = CS_CFG_MATCH_CLASS_SRC_ETM4 | CS_CFG_MATCH_CAP_TRCEXTOUT,
+	.nr_regs = ARRAY_SIZE(extout_pulse_regs),
+	.regs_desc = extout_pulse_regs,
+};

[Severity: Medium]
Can extout_pulse_etm4x load on a 1-event ETE that only implements event 0 and TRCEXTOUT0, where event 1 (TRCEVENTCTL0R[15:8]) and TRCEXTOUT1 do not exist?

In drivers/hwtracing/coresight/coresight-etm4x-core.c, on an ETE where TRCIDR4.NUMRSPAIR > 0 and TRCIDR0.NUMEVENT == 0, etm4_init_arch_data() sets drvdata->caps.nr_event = 1. When etm4_cscfg_register() checks etm4_pmu_counts_extout(), it only verifies the events up to caps.nr_event:

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

When drvdata->caps.nr_event == 1 and ARMV8_PMUV3_PERFCTR_TRCEXTOUT0 is implemented, etm4_pmu_counts_extout() returns true and sets CS_CFG_MATCH_CAP_TRCEXTOUT without checking TRCEXTOUT1.

During feature loading in drivers/hwtracing/coresight/coresight-etm4x-cfg.c, etm4_cfg_load_feature() -> etm4_cfg_map_reg_offset() maps TRCEVENTCTL0R unconditionally via CHECKREG(TRCEVENTCTL0R, eventctrl0) without checking whether drvdata->caps.nr_event covers the event fields masked by the feature.

Should etm4_cfg_load_feature() or the capability check verify that drvdata->caps.nr_event >= 2 before allowing extout_pulse_etm4x to load and program TRCEVENTCTL0R[15:8]?

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=7
#37 lore raw

v4 cover coresight: Pulse an ETM external output for a PMU event

In reply to Amir Ayupov

Add an ETMv4 configuration, pmu_pulse, that drives trace unit external output 1 on every traced cycle, so a PMU event counting it (TRCEXTOUT1) can end a fixed-length ETM window, for example with aux-action=pause. The feature only loads on an ETE whose PMU counts its external outputs.

Patch 1 is Leo's fix for TRCIDR0.NUMEVENT decoding, which patch 6 relies on for the number of external outputs.

Changes in v4:
- Fix the arm64 build: v3 defined pmuv3_event_implemented() in linux/perf/arm_pmuv3.h after including asm/arm_pmuv3.h, which broke files that include asm/arm_pmuv3.h directly, such as arch/arm64/kernel/cpufeature.c. Move it to the arm64 asm/arm_pmuv3.h, after the helpers it uses.
Breakage reported by kernel test robot.
- Link to v3: https://lore.kernel.org/r/[email protected]

Changes in v3:
- Rebase onto coresight next, which moves the capability fields into drvdata->caps (Leo).
- Carry Leo's "coresight: etm4x: Fix event count decoding" (Leo).
- Add Leo's Reviewed-by to "Fail to enable a configuration not loaded on the device".
- Define CS_CFG_MATCH_CLASS_MASK and CS_CFG_MATCH_CAP_MASK with GENMASK_U32() and split the match check into early returns (Leo). The class check stays an intersection, as ETMv4 devices register with SRC_ALL | SRC_ETM4 while the built-in features only set SRC_ETM4.
- Remove the unused CS_CFG_MATCH_INST_ANY in a separate patch (Leo).
- Replace the per-output CS_CFG_MATCH_CAP_PMU_EXTOUT(n) bits with a single CS_CFG_MATCH_CAP_TRCEXTOUT, set on ETE only (Leo, James).
- Check the PMU events through a new pmuv3_event_implemented() helper instead of open-coding PMCEID0_EL0 in etm4x (James).
- Use PMU-agnostic event names in the documentation example (Daniel).
- Add Daniel's Reviewed-by to "Add pmu_pulse/extout_pulse".
- Link to v2: https://lore.kernel.org/r/[email protected]

Amir Ayupov (6):
coresight: syscfg: Fail to enable a configuration not loaded on the
device
coresight: syscfg: Match feature capabilities separately from device
class
coresight: syscfg: Remove unused CS_CFG_MATCH_INST_ANY
perf: arm_pmuv3: Add pmuv3_event_implemented()
coresight: etm4x: Report whether the PMU counts the external outputs
coresight: Add pmu_pulse/extout_pulse

Leo Yan (1):
coresight: etm4x: Fix event count decoding

 .../trace/coresight/coresight-config.rst      |  5 ++
 .../trace/coresight/coresight-perf.rst        | 15 ++++
 arch/arm64/include/asm/arm_pmuv3.h            | 19 ++++
 drivers/hwtracing/coresight/Makefile          |  1 +
 .../coresight/coresight-cfg-pmu-pulse.c       | 55 ++++++++++++
 .../coresight/coresight-cfg-preload.c         |  2 +
 .../coresight/coresight-cfg-preload.h         |  2 +
 .../hwtracing/coresight/coresight-config.h    | 11 ++-
 .../hwtracing/coresight/coresight-etm4x-cfg.c |  6 +-
 .../coresight/coresight-etm4x-core.c          | 39 +++++++-
 .../coresight/coresight-etm4x-sysfs.c         | 29 +++---
 drivers/hwtracing/coresight/coresight-etm4x.h |  3 +
 .../coresight/coresight-syscfg-configfs.c     |  3 +
 .../hwtracing/coresight/coresight-syscfg.c    | 90 +++++++++++--------
 include/linux/perf/arm_pmu.h                  |  1 -
 include/linux/perf/arm_pmuv3.h                |  3 +
 16 files changed, 229 insertions(+), 55 deletions(-)
 create mode 100644 drivers/hwtracing/coresight/coresight-cfg-pmu-pulse.c

base-commit: 343cfcbb3ecfdb80aa576a428cfa3b65ad783842

Signature · 1 line
2.52.0
#38 lore raw

PATCH v4 1/7 coresight: etm4x: Fix event count decoding

From: Leo Yan <[email protected]>

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.

---
 .../coresight/coresight-etm4x-core.c          | 13 +++++++--
 .../coresight/coresight-etm4x-sysfs.c         | 29 ++++++++++---------
 2 files changed, 27 insertions(+), 15 deletions(-)
drivers/hwtracing/coresight/coresight-etm4x-core.c +11 -2
index e21be6468e954..af017bd8a5477 100644
@@ -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
drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +16 -13
index db9e603f97ba8..fb38f0102290a 100644
@@ -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 |
Signature · 1 line
2.52.0
#39 lore raw

Re: [PATCH v4 1/7] coresight: etm4x: Fix event count decoding

Sashiko has reviewed this patch and found no issues.
Quoted 14 lines

From: Leo Yan <[email protected]>

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.

Quoted 8 lines

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.

Sashiko has reviewed this patch and found no issues.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
reviewer Reviewed-by on v4 1/7
#40 lore raw

Re: [PATCH v4 1/7] coresight: etm4x: Fix event count decoding

In reply to Amir Ayupov
Quoted 111 lines · Amir Ayupov

From: Leo Yan <[email protected]>

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.

---
  .../coresight/coresight-etm4x-core.c          | 13 +++++++--
  .../coresight/coresight-etm4x-sysfs.c         | 29 ++++++++++---------
  2 files changed, 27 insertions(+), 15 deletions(-)
drivers/hwtracing/coresight/coresight-etm4x-core.c +11 -2
index e21be6468e954..af017bd8a5477 100644
@@ -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
drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +14 -12
index db9e603f97ba8..fb38f0102290a 100644
@@ -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:

drivers/hwtracing/coresight/coresight-etm4x-sysfs.c static ssize_t event_instren_store(struct device *dev, · line 589

Quoted 10 lines
drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +2 -1
+		/* 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 |
#41 lore raw

PATCH v4 2/7 coresight: syscfg: Fail to enable a configuration not loaded on the device

In reply to Amir Ayupov

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
---
 .../hwtracing/coresight/coresight-syscfg.c    | 53 ++++++++++---------
 1 file changed, 28 insertions(+), 25 deletions(-)
drivers/hwtracing/coresight/coresight-syscfg.c +28 -25
index 2bfdd7b45e49c..a816c22c87bc8 100644
@@ -1088,36 +1088,39 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
 	raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
 
 	/*
-	 * If found, attempt to enable
+	 * The configuration is active but not loaded on this device, because
+	 * none of its features match the device. Fail rather than trace
+	 * without it.
 	 */
-	if (config_csdev_active) {
+	if (!config_csdev_active)
+		return -EINVAL;
+
+	/*
+	 * Call the generic routine that will program up the internal
+	 * driver structures prior to programming up the hardware.
+	 * This routine takes the driver spinlock saved in the configs.
+	 */
+	err = cscfg_csdev_enable_config(config_csdev_active, preset);
+	if (!err) {
 		/*
-		 * Call the generic routine that will program up the internal
-		 * driver structures prior to programming up the hardware.
-		 * This routine takes the driver spinlock saved in the configs.
+		 * Successful programming. Check the active_cscfg_ctxt
+		 * pointer to ensure no pre-emption disabled it via
+		 * cscfg_csdev_disable_active_config() before
+		 * we could start.
+		 *
+		 * Set enabled if OK, err if not.
 		 */
-		err = cscfg_csdev_enable_config(config_csdev_active, preset);
-		if (!err) {
-			/*
-			 * Successful programming. Check the active_cscfg_ctxt
-			 * pointer to ensure no pre-emption disabled it via
-			 * cscfg_csdev_disable_active_config() before
-			 * we could start.
-			 *
-			 * Set enabled if OK, err if not.
-			 */
-			raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
-			if (csdev->active_cscfg_ctxt)
-				config_csdev_active->enabled = true;
-			else
-				err = -EBUSY;
-			raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
-		}
-
-		if (err)
-			cscfg_config_desc_put(config_desc);
+		raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
+		if (csdev->active_cscfg_ctxt)
+			config_csdev_active->enabled = true;
+		else
+			err = -EBUSY;
+		raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
 	}
 
+	if (err)
+		cscfg_config_desc_put(config_desc);
+
 	return err;
 }
 EXPORT_SYMBOL_GPL(cscfg_csdev_enable_active_config);
Signature · 1 line
2.52.0
#42 lore raw

Re: [PATCH v4 2/7] coresight: syscfg: Fail to enable a configuration not loaded on the device

Sashiko has reviewed this patch and found no issues.
Quoted 6 lines

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.

Quoted 7 lines

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

Sashiko has reviewed this patch and found no issues.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
#43 lore raw

PATCH v4 3/7 coresight: syscfg: Match feature capabilities separately from device class

In reply to Amir Ayupov

A feature loads on a device when the two share any match flag. That works for device classes, where a feature wants any one of them, but not for capabilities a device may or may not have: a feature that sets a class and a capability would still load on a device of that class without the capability.

Split the match flags into CS_CFG_MATCH_CLASS_MASK for device classes and CS_CFG_MATCH_CAP_MASK for capabilities. A feature now loads on a device that shares one of its classes and has all of its capabilities. Check this once in cscfg_load_feat_csdev(), which both the feature and the device registration paths call. No capability flags are defined yet, so matching is unchanged.

Assisted-by Devmate:Opus-5.5
---
 .../hwtracing/coresight/coresight-config.h    |  8 ++++
 .../hwtracing/coresight/coresight-syscfg.c    | 37 +++++++++++++------
 2 files changed, 34 insertions(+), 11 deletions(-)
drivers/hwtracing/coresight/coresight-config.h +8 -0
index ae6295e308131..f04e73b91d9a6 100644
@@ -7,6 +7,7 @@
 #ifndef _CORESIGHT_CORESIGHT_CONFIG_H
 #define _CORESIGHT_CORESIGHT_CONFIG_H
 
+#include <linux/bits.h>
 #include <linux/cleanup.h>
 #include <linux/coresight.h>
 #include <linux/types.h>
@@ -30,6 +31,13 @@
  */
 #define CS_CFG_MATCH_CLASS_SRC_ALL	0x0001	/* match any source */
 #define CS_CFG_MATCH_CLASS_SRC_ETM4	0x0002	/* match any ETMv4 device */
+#define CS_CFG_MATCH_CLASS_MASK		GENMASK_U32(7, 0)
+
+/*
+ * flags defining device capabilities a feature can require. A feature loads on
+ * a device that matches one of its classes and has all of its capabilities.
+ */
+#define CS_CFG_MATCH_CAP_MASK		GENMASK_U32(15, 8)
 
 /* flags defining device instance matching - used in config match desc data. */
 #define CS_CFG_MATCH_INST_ANY		0x80000000 /* any instance of a class */
drivers/hwtracing/coresight/coresight-syscfg.c +26 -11
index a816c22c87bc8..3ee104e94a4cd 100644
@@ -171,8 +171,22 @@ cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc
 	return feat_csdev;
 }
 
-/* load one feature into one coresight device */
+static bool cscfg_match_feat_csdev(u32 feat_flags, u32 csdev_flags)
+{
+	/* The device must be in one of the feature's classes */
+	if (!(feat_flags & csdev_flags & CS_CFG_MATCH_CLASS_MASK))
+		return false;
+
+	/* The device must have every capability the feature requires */
+	if (feat_flags & ~csdev_flags & CS_CFG_MATCH_CAP_MASK)
+		return false;
+
+	return true;
+}
+
+/* Load the feature into the device if it matches, otherwise skip it. */
 static int cscfg_load_feat_csdev(struct coresight_device *csdev,
+				 u32 match_flags,
 				 struct cscfg_feature_desc *feat_desc,
 				 struct cscfg_csdev_feat_ops *ops)
 {
@@ -183,6 +197,9 @@ static int cscfg_load_feat_csdev(struct coresight_device *csdev,
 	if (!ops->load_feat)
 		return -EINVAL;
 
+	if (!cscfg_match_feat_csdev(feat_desc->match_flags, match_flags))
+		return 0;
+
 	feat_csdev = cscfg_alloc_csdev_feat(csdev, feat_desc);
 	if (!feat_csdev)
 		return -ENOMEM;
@@ -212,11 +229,11 @@ static int cscfg_add_feat_to_csdevs(struct cscfg_feature_desc *feat_desc)
 	int err;
 
 	list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
-		if (csdev_item->match_flags & feat_desc->match_flags) {
-			err = cscfg_load_feat_csdev(csdev_item->csdev, feat_desc, &csdev_item->ops);
-			if (err)
-				return err;
-		}
+		err = cscfg_load_feat_csdev(csdev_item->csdev,
+					    csdev_item->match_flags, feat_desc,
+					    &csdev_item->ops);
+		if (err)
+			return err;
 	}
 	return 0;
 }
@@ -739,11 +756,9 @@ static int cscfg_add_feats_csdev(struct coresight_device *csdev,
 		return -EINVAL;
 
 	list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
-		if (feat_desc->match_flags & match_flags) {
-			err = cscfg_load_feat_csdev(csdev, feat_desc, ops);
-			if (err)
-				break;
-		}
+		err = cscfg_load_feat_csdev(csdev, match_flags, feat_desc, ops);
+		if (err)
+			break;
 	}
 	return err;
 }
Signature · 1 line
2.52.0
#44 lore raw

Re: [PATCH v4 3/7] coresight: syscfg: Match feature capabilities separately from device class

Sashiko has reviewed this patch and found no issues.
Quoted 13 lines

A feature loads on a device when the two share any match flag. That works for device classes, where a feature wants any one of them, but not for capabilities a device may or may not have: a feature that sets a class and a capability would still load on a device of that class without the capability.

Split the match flags into CS_CFG_MATCH_CLASS_MASK for device classes and CS_CFG_MATCH_CAP_MASK for capabilities. A feature now loads on a device that shares one of its classes and has all of its capabilities. Check this once in cscfg_load_feat_csdev(), which both the feature and the device registration paths call. No capability flags are defined yet, so matching is unchanged.

Quoted 2 lines
Assisted-by Devmate:Opus-5.5

Sashiko has reviewed this patch and found no issues.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
reviewer Reviewed-by on v4 3/7
#45 lore raw

Re: [PATCH v4 3/7] coresight: syscfg: Match feature capabilities separately from device class

In reply to Amir Ayupov
Quoted 106 lines · Amir Ayupov

A feature loads on a device when the two share any match flag. That works for device classes, where a feature wants any one of them, but not for capabilities a device may or may not have: a feature that sets a class and a capability would still load on a device of that class without the capability.

Split the match flags into CS_CFG_MATCH_CLASS_MASK for device classes and CS_CFG_MATCH_CAP_MASK for capabilities. A feature now loads on a device that shares one of its classes and has all of its capabilities. Check this once in cscfg_load_feat_csdev(), which both the feature and the device registration paths call. No capability flags are defined yet, so matching is unchanged.

Assisted-by Devmate:Opus-5.5
---
  .../hwtracing/coresight/coresight-config.h    |  8 ++++
  .../hwtracing/coresight/coresight-syscfg.c    | 37 +++++++++++++------
  2 files changed, 34 insertions(+), 11 deletions(-)
drivers/hwtracing/coresight/coresight-config.h +8 -0
index ae6295e308131..f04e73b91d9a6 100644
@@ -7,6 +7,7 @@
  #ifndef _CORESIGHT_CORESIGHT_CONFIG_H
  #define _CORESIGHT_CORESIGHT_CONFIG_H
 
+#include <linux/bits.h>
  #include <linux/cleanup.h>
  #include <linux/coresight.h>
  #include <linux/types.h>
@@ -30,6 +31,13 @@
   */
  #define CS_CFG_MATCH_CLASS_SRC_ALL	0x0001	/* match any source */
  #define CS_CFG_MATCH_CLASS_SRC_ETM4	0x0002	/* match any ETMv4 device */
+#define CS_CFG_MATCH_CLASS_MASK		GENMASK_U32(7, 0)
+
+/*
+ * flags defining device capabilities a feature can require. A feature loads on
+ * a device that matches one of its classes and has all of its capabilities.
+ */
+#define CS_CFG_MATCH_CAP_MASK		GENMASK_U32(15, 8)
 
  /* flags defining device instance matching - used in config match desc data. */
  #define CS_CFG_MATCH_INST_ANY		0x80000000 /* any instance of a class */
drivers/hwtracing/coresight/coresight-syscfg.c +23 -7
index a816c22c87bc8..3ee104e94a4cd 100644
@@ -171,8 +171,22 @@ cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc
  	return feat_csdev;
  }
 
-/* load one feature into one coresight device */
+static bool cscfg_match_feat_csdev(u32 feat_flags, u32 csdev_flags)
+{
+	/* The device must be in one of the feature's classes */
+	if (!(feat_flags & csdev_flags & CS_CFG_MATCH_CLASS_MASK))
+		return false;
+
+	/* The device must have every capability the feature requires */
+	if (feat_flags & ~csdev_flags & CS_CFG_MATCH_CAP_MASK)
+		return false;
+
+	return true;
+}
+
+/* Load the feature into the device if it matches, otherwise skip it. */
  static int cscfg_load_feat_csdev(struct coresight_device *csdev,
+				 u32 match_flags,
  				 struct cscfg_feature_desc *feat_desc,
  				 struct cscfg_csdev_feat_ops *ops)
  {
@@ -183,6 +197,9 @@ static int cscfg_load_feat_csdev(struct coresight_device *csdev,
  	if (!ops->load_feat)
  		return -EINVAL;
 
+	if (!cscfg_match_feat_csdev(feat_desc->match_flags, match_flags))
+		return 0;
+
  	feat_csdev = cscfg_alloc_csdev_feat(csdev, feat_desc);
  	if (!feat_csdev)
  		return -ENOMEM;
@@ -212,11 +229,11 @@ static int cscfg_add_feat_to_csdevs(struct cscfg_feature_desc *feat_desc)
  	int err;
 
  	list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
-		if (csdev_item->match_flags & feat_desc->match_flags) {
-			err = cscfg_load_feat_csdev(csdev_item->csdev, feat_desc, &csdev_item->ops);
-			if (err)
-				return err;
-		}
+		err = cscfg_load_feat_csdev(csdev_item->csdev,
+					    csdev_item->match_flags, feat_desc,
+					    &csdev_item->ops);
+		if (err)
+			return err;
  	}
  	return 0;
  }
@@ -739,11 +756,9 @@ static int cscfg_add_feats_csdev(struct coresight_device *csdev,
  		return -EINVAL;
 
  	list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
-		if (feat_desc->match_flags & match_flags) {

drivers/hwtracing/coresight/coresight-syscfg.c static int cscfg_add_feats_csdev(struct coresight_device *csdev, · line 764

Quoted 10 lines
drivers/hwtracing/coresight/coresight-syscfg.c +3 -4
-			err = cscfg_load_feat_csdev(csdev, feat_desc, ops);
-			if (err)
-				break;
-		}
+		err = cscfg_load_feat_csdev(csdev, match_flags, feat_desc, ops);
+		if (err)
+			break;
  	}
  	return err;
  }
maintainer
#46 lore raw

Re: [PATCH v4 3/7] coresight: syscfg: Match feature capabilities separately from device class

In reply to Amir Ayupov
Quoted 54 lines · Amir Ayupov

A feature loads on a device when the two share any match flag. That works for device classes, where a feature wants any one of them, but not for capabilities a device may or may not have: a feature that sets a class and a capability would still load on a device of that class without the capability.

Split the match flags into CS_CFG_MATCH_CLASS_MASK for device classes and CS_CFG_MATCH_CAP_MASK for capabilities. A feature now loads on a device that shares one of its classes and has all of its capabilities. Check this once in cscfg_load_feat_csdev(), which both the feature and the device registration paths call. No capability flags are defined yet, so matching is unchanged.

Assisted-by Devmate:Opus-5.5
---
  .../hwtracing/coresight/coresight-config.h    |  8 ++++
  .../hwtracing/coresight/coresight-syscfg.c    | 37 +++++++++++++------
  2 files changed, 34 insertions(+), 11 deletions(-)
drivers/hwtracing/coresight/coresight-config.h +8 -0
index ae6295e308131..f04e73b91d9a6 100644
@@ -7,6 +7,7 @@
  #ifndef _CORESIGHT_CORESIGHT_CONFIG_H
  #define _CORESIGHT_CORESIGHT_CONFIG_H
 
+#include <linux/bits.h>
  #include <linux/cleanup.h>
  #include <linux/coresight.h>
  #include <linux/types.h>
@@ -30,6 +31,13 @@
   */
  #define CS_CFG_MATCH_CLASS_SRC_ALL	0x0001	/* match any source */
  #define CS_CFG_MATCH_CLASS_SRC_ETM4	0x0002	/* match any ETMv4 device */
+#define CS_CFG_MATCH_CLASS_MASK		GENMASK_U32(7, 0)
+
+/*
+ * flags defining device capabilities a feature can require. A feature loads on
+ * a device that matches one of its classes and has all of its capabilities.
+ */
+#define CS_CFG_MATCH_CAP_MASK		GENMASK_U32(15, 8)
 
  /* flags defining device instance matching - used in config match desc data. */
  #define CS_CFG_MATCH_INST_ANY		0x80000000 /* any instance of a class */
drivers/hwtracing/coresight/coresight-syscfg.c +0 -0
index a816c22c87bc8..3ee104e94a4cd 100644
@@ -171,8 +171,22 @@ cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc
  	return feat_csdev;
  }
 

drivers/hwtracing/coresight/coresight-syscfg.c cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc · line 182

Quoted 10 lines
drivers/hwtracing/coresight/coresight-syscfg.c +9 -1
-/* load one feature into one coresight device */
+static bool cscfg_match_feat_csdev(u32 feat_flags, u32 csdev_flags)
+{
+	/* The device must be in one of the feature's classes */
+	if (!(feat_flags & csdev_flags & CS_CFG_MATCH_CLASS_MASK))
+		return false;
+
+	/* The device must have every capability the feature requires */
+	if (feat_flags & ~csdev_flags & CS_CFG_MATCH_CAP_MASK)
+		return false;

Please could you address the following comment ?

https://lore.kernel.org/linux-arm-kernel/[email protected]/

Cheers
Suzuki

Quoted 52 lines
drivers/hwtracing/coresight/coresight-syscfg.c +17 -10
+
+	return true;
+}
+
+/* Load the feature into the device if it matches, otherwise skip it. */
  static int cscfg_load_feat_csdev(struct coresight_device *csdev,
+				 u32 match_flags,
  				 struct cscfg_feature_desc *feat_desc,
  				 struct cscfg_csdev_feat_ops *ops)
  {
@@ -183,6 +197,9 @@ static int cscfg_load_feat_csdev(struct coresight_device *csdev,
  	if (!ops->load_feat)
  		return -EINVAL;
 
+	if (!cscfg_match_feat_csdev(feat_desc->match_flags, match_flags))
+		return 0;
+
  	feat_csdev = cscfg_alloc_csdev_feat(csdev, feat_desc);
  	if (!feat_csdev)
  		return -ENOMEM;
@@ -212,11 +229,11 @@ static int cscfg_add_feat_to_csdevs(struct cscfg_feature_desc *feat_desc)
  	int err;
 
  	list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
-		if (csdev_item->match_flags & feat_desc->match_flags) {
-			err = cscfg_load_feat_csdev(csdev_item->csdev, feat_desc, &csdev_item->ops);
-			if (err)
-				return err;
-		}
+		err = cscfg_load_feat_csdev(csdev_item->csdev,
+					    csdev_item->match_flags, feat_desc,
+					    &csdev_item->ops);
+		if (err)
+			return err;
  	}
  	return 0;
  }
@@ -739,11 +756,9 @@ static int cscfg_add_feats_csdev(struct coresight_device *csdev,
  		return -EINVAL;
 
  	list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
-		if (feat_desc->match_flags & match_flags) {
-			err = cscfg_load_feat_csdev(csdev, feat_desc, ops);
-			if (err)
-				break;
-		}
+		err = cscfg_load_feat_csdev(csdev, match_flags, feat_desc, ops);
+		if (err)
+			break;
  	}
  	return err;
  }
#47 lore raw

PATCH v4 4/7 coresight: syscfg: Remove unused CS_CFG_MATCH_INST_ANY

In reply to Amir Ayupov

CS_CFG_MATCH_INST_ANY has been defined since the system configuration was introduced but is not used by any configuration, feature or device. Remove it.

Assisted-by Devmate:Opus-5.5
---
 drivers/hwtracing/coresight/coresight-config.h | 3 ---
 1 file changed, 3 deletions(-)
drivers/hwtracing/coresight/coresight-config.h +0 -3
index f04e73b91d9a6..220bc54f8e5e1 100644
@@ -39,9 +39,6 @@
  */
 #define CS_CFG_MATCH_CAP_MASK		GENMASK_U32(15, 8)
 
-/* flags defining device instance matching - used in config match desc data. */
-#define CS_CFG_MATCH_INST_ANY		0x80000000 /* any instance of a class */
-
 /*
  * Limit number of presets in a configuration
  * This is related to the number of bits (4) we use to select the preset on
Signature · 1 line
2.52.0
#48 lore raw

Re: [PATCH v4 4/7] coresight: syscfg: Remove unused CS_CFG_MATCH_INST_ANY

Sashiko has reviewed this patch and found no issues.
Quoted 7 lines

CS_CFG_MATCH_INST_ANY has been defined since the system configuration was introduced but is not used by any configuration, feature or device. Remove it.

Assisted-by Devmate:Opus-5.5

Sashiko has reviewed this patch and found no issues.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=4
reviewer Reviewed-by on v4 4/7
#49 lore raw

Re: [PATCH v4 4/7] coresight: syscfg: Remove unused CS_CFG_MATCH_INST_ANY

In reply to Amir Ayupov
Quoted 16 lines · Amir Ayupov

CS_CFG_MATCH_INST_ANY has been defined since the system configuration was introduced but is not used by any configuration, feature or device. Remove it.

Assisted-by Devmate:Opus-5.5
---
  drivers/hwtracing/coresight/coresight-config.h | 3 ---
  1 file changed, 3 deletions(-)
drivers/hwtracing/coresight/coresight-config.h +0 -0
index f04e73b91d9a6..220bc54f8e5e1 100644

drivers/hwtracing/coresight/coresight-config.h line 44

Quoted 9 lines
drivers/hwtracing/coresight/coresight-config.h +0 -3
@@ -39,9 +39,6 @@
   */
  #define CS_CFG_MATCH_CAP_MASK		GENMASK_U32(15, 8)
 
-/* flags defining device instance matching - used in config match desc data. */
-#define CS_CFG_MATCH_INST_ANY		0x80000000 /* any instance of a class */
-
  /*
   * Limit number of presets in a configuration
   * This is related to the number of bits (4) we use to select the preset on
#50 lore raw

PATCH v4 5/7 perf: arm_pmuv3: Add pmuv3_event_implemented()

In reply to Amir Ayupov

Drivers outside the PMU driver may need to know whether the local CPU's PMU implements a common event before relying on it, for example a trace unit driver checking that the PMU counts its external outputs as TRCEXTOUTn.

Add pmuv3_event_implemented() to the arm64 asm/arm_pmuv3.h, next to read_pmceid0() and read_pmceid1(). It reads PMCEID0/1 on the calling CPU:
events 0x0000-0x003f are reported in bits [31:0], and the common events from ARMV8_PMUV3_EXT_COMMON_EVENT_BASE in bits [63:32] from PMUv3p1. Move ARMV8_PMUV3_EXT_COMMON_EVENT_BASE next to the event numbers in linux/perf/arm_pmuv3.h so it is available without CONFIG_ARM_PMU.

Assisted-by Devmate:Opus-5.5
---
 arch/arm64/include/asm/arm_pmuv3.h | 19 +++++++++++++++++++
 include/linux/perf/arm_pmu.h       |  1 -
 include/linux/perf/arm_pmuv3.h     |  3 +++
 3 files changed, 22 insertions(+), 1 deletion(-)
arch/arm64/include/asm/arm_pmuv3.h +19 -0
index 8a777dec8d88a..acd62c4f16743 100644
@@ -173,6 +173,25 @@ static inline bool pmuv3_implemented(int pmuver)
 		 pmuver == ID_AA64DFR0_EL1_PMUVer_NI);
 }
 
+/*
+ * Whether this CPU's PMU implements a common event, as reported by
+ * PMCEID{0,1}: events 0x0000-0x003f in bits [31:0], and from PMUv3p1 events
+ * 0x4000-0x403f in bits [63:32], which read as zero before PMUv3p1.
+ * Must run on the CPU whose PMU is queried.
+ */
+static inline bool pmuv3_event_implemented(u16 event)
+{
+	bool ext = event >= ARMV8_PMUV3_EXT_COMMON_EVENT_BASE;
+	u16 id = ext ? event - ARMV8_PMUV3_EXT_COMMON_EVENT_BASE : event;
+	u64 pmceid;
+
+	if (id >= 64 || !pmuv3_implemented(read_pmuver()))
+		return false;
+
+	pmceid = id < 32 ? read_pmceid0() : read_pmceid1();
+	return pmceid & BIT_ULL(id % 32 + (ext ? 32 : 0));
+}
+
 static inline bool is_pmuv3p4(int pmuver)
 {
 	return pmuver >= ID_AA64DFR0_EL1_PMUVer_V3P4;
include/linux/perf/arm_pmu.h +0 -1
index 02d2c7f45b527..792283d29d7b5 100644
@@ -124,7 +124,6 @@ struct arm_pmu {
 	u64		reg_brbidr;
 #define ARMV8_PMUV3_MAX_COMMON_EVENTS		0x40
 	DECLARE_BITMAP(pmceid_bitmap, ARMV8_PMUV3_MAX_COMMON_EVENTS);
-#define ARMV8_PMUV3_EXT_COMMON_EVENT_BASE	0x4000
 	DECLARE_BITMAP(pmceid_ext_bitmap, ARMV8_PMUV3_MAX_COMMON_EVENTS);
 
 	/* Only to be used by ACPI probing code */
include/linux/perf/arm_pmuv3.h +3 -0
index d698efba28a27..c21f185a283d6 100644
@@ -78,6 +78,9 @@
 #define ARMV8_PMUV3_PERFCTR_STALL_SLOT_FRONTEND			0x003E
 #define ARMV8_PMUV3_PERFCTR_STALL_SLOT				0x003F
 
+/* Base of the common events reported in PMCEID{0,1}[63:32] from PMUv3p1 */
+#define ARMV8_PMUV3_EXT_COMMON_EVENT_BASE			0x4000
+
 /* Statistical profiling extension microarchitectural events */
 #define ARMV8_SPE_PERFCTR_SAMPLE_POP				0x4000
 #define ARMV8_SPE_PERFCTR_SAMPLE_FEED				0x4001
Signature · 1 line
2.52.0
#51 lore raw

Re: [PATCH v4 5/7] perf: arm_pmuv3: Add pmuv3_event_implemented()

Sashiko has reviewed this patch and found no issues.
Quoted 12 lines

Drivers outside the PMU driver may need to know whether the local CPU's PMU implements a common event before relying on it, for example a trace unit driver checking that the PMU counts its external outputs as TRCEXTOUTn.

Add pmuv3_event_implemented() to the arm64 asm/arm_pmuv3.h, next to read_pmceid0() and read_pmceid1(). It reads PMCEID0/1 on the calling CPU:
events 0x0000-0x003f are reported in bits [31:0], and the common events from ARMV8_PMUV3_EXT_COMMON_EVENT_BASE in bits [63:32] from PMUv3p1. Move ARMV8_PMUV3_EXT_COMMON_EVENT_BASE next to the event numbers in linux/perf/arm_pmuv3.h so it is available without CONFIG_ARM_PMU.

Quoted 3 lines
Assisted-by Devmate:Opus-5.5

Sashiko has reviewed this patch and found no issues.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=5
reviewer Reviewed-by on v4 5/7
#52 lore raw

Re: [PATCH v4 5/7] perf: arm_pmuv3: Add pmuv3_event_implemented()

In reply to Amir Ayupov
Quoted 68 lines · Amir Ayupov

Drivers outside the PMU driver may need to know whether the local CPU's PMU implements a common event before relying on it, for example a trace unit driver checking that the PMU counts its external outputs as TRCEXTOUTn.

Add pmuv3_event_implemented() to the arm64 asm/arm_pmuv3.h, next to read_pmceid0() and read_pmceid1(). It reads PMCEID0/1 on the calling CPU:
events 0x0000-0x003f are reported in bits [31:0], and the common events from ARMV8_PMUV3_EXT_COMMON_EVENT_BASE in bits [63:32] from PMUv3p1. Move ARMV8_PMUV3_EXT_COMMON_EVENT_BASE next to the event numbers in linux/perf/arm_pmuv3.h so it is available without CONFIG_ARM_PMU.

Assisted-by Devmate:Opus-5.5
---
  arch/arm64/include/asm/arm_pmuv3.h | 19 +++++++++++++++++++
  include/linux/perf/arm_pmu.h       |  1 -
  include/linux/perf/arm_pmuv3.h     |  3 +++
  3 files changed, 22 insertions(+), 1 deletion(-)
arch/arm64/include/asm/arm_pmuv3.h +19 -0
index 8a777dec8d88a..acd62c4f16743 100644
@@ -173,6 +173,25 @@ static inline bool pmuv3_implemented(int pmuver)
  		 pmuver == ID_AA64DFR0_EL1_PMUVer_NI);
  }
 
+/*
+ * Whether this CPU's PMU implements a common event, as reported by
+ * PMCEID{0,1}: events 0x0000-0x003f in bits [31:0], and from PMUv3p1 events
+ * 0x4000-0x403f in bits [63:32], which read as zero before PMUv3p1.
+ * Must run on the CPU whose PMU is queried.
+ */
+static inline bool pmuv3_event_implemented(u16 event)
+{
+	bool ext = event >= ARMV8_PMUV3_EXT_COMMON_EVENT_BASE;
+	u16 id = ext ? event - ARMV8_PMUV3_EXT_COMMON_EVENT_BASE : event;
+	u64 pmceid;
+
+	if (id >= 64 || !pmuv3_implemented(read_pmuver()))
+		return false;
+
+	pmceid = id < 32 ? read_pmceid0() : read_pmceid1();
+	return pmceid & BIT_ULL(id % 32 + (ext ? 32 : 0));
+}
+
  static inline bool is_pmuv3p4(int pmuver)
  {
  	return pmuver >= ID_AA64DFR0_EL1_PMUVer_V3P4;
include/linux/perf/arm_pmu.h +0 -1
index 02d2c7f45b527..792283d29d7b5 100644
@@ -124,7 +124,6 @@ struct arm_pmu {
  	u64		reg_brbidr;
  #define ARMV8_PMUV3_MAX_COMMON_EVENTS		0x40
  	DECLARE_BITMAP(pmceid_bitmap, ARMV8_PMUV3_MAX_COMMON_EVENTS);
-#define ARMV8_PMUV3_EXT_COMMON_EVENT_BASE	0x4000
  	DECLARE_BITMAP(pmceid_ext_bitmap, ARMV8_PMUV3_MAX_COMMON_EVENTS);
 
  	/* Only to be used by ACPI probing code */
include/linux/perf/arm_pmuv3.h +0 -0
index d698efba28a27..c21f185a283d6 100644

include/linux/perf/arm_pmuv3.h line 86

Quoted 9 lines
include/linux/perf/arm_pmuv3.h +3 -0
@@ -78,6 +78,9 @@
  #define ARMV8_PMUV3_PERFCTR_STALL_SLOT_FRONTEND			0x003E
  #define ARMV8_PMUV3_PERFCTR_STALL_SLOT				0x003F
 
+/* Base of the common events reported in PMCEID{0,1}[63:32] from PMUv3p1 */
+#define ARMV8_PMUV3_EXT_COMMON_EVENT_BASE			0x4000
+
  /* Statistical profiling extension microarchitectural events */
  #define ARMV8_SPE_PERFCTR_SAMPLE_POP				0x4000
  #define ARMV8_SPE_PERFCTR_SAMPLE_FEED				0x4001
maintainer
#53 lore raw

Re: [PATCH v4 5/7] perf: arm_pmuv3: Add pmuv3_event_implemented()

In reply to Amir Ayupov
Quoted 56 lines · Amir Ayupov

Drivers outside the PMU driver may need to know whether the local CPU's PMU implements a common event before relying on it, for example a trace unit driver checking that the PMU counts its external outputs as TRCEXTOUTn.

Add pmuv3_event_implemented() to the arm64 asm/arm_pmuv3.h, next to read_pmceid0() and read_pmceid1(). It reads PMCEID0/1 on the calling CPU:
events 0x0000-0x003f are reported in bits [31:0], and the common events from ARMV8_PMUV3_EXT_COMMON_EVENT_BASE in bits [63:32] from PMUv3p1. Move ARMV8_PMUV3_EXT_COMMON_EVENT_BASE next to the event numbers in linux/perf/arm_pmuv3.h so it is available without CONFIG_ARM_PMU.

Assisted-by Devmate:Opus-5.5
---
  arch/arm64/include/asm/arm_pmuv3.h | 19 +++++++++++++++++++
  include/linux/perf/arm_pmu.h       |  1 -
  include/linux/perf/arm_pmuv3.h     |  3 +++
  3 files changed, 22 insertions(+), 1 deletion(-)
arch/arm64/include/asm/arm_pmuv3.h +19 -0
index 8a777dec8d88a..acd62c4f16743 100644
@@ -173,6 +173,25 @@ static inline bool pmuv3_implemented(int pmuver)
  		 pmuver == ID_AA64DFR0_EL1_PMUVer_NI);
  }
 
+/*
+ * Whether this CPU's PMU implements a common event, as reported by
+ * PMCEID{0,1}: events 0x0000-0x003f in bits [31:0], and from PMUv3p1 events
+ * 0x4000-0x403f in bits [63:32], which read as zero before PMUv3p1.
+ * Must run on the CPU whose PMU is queried.
+ */
+static inline bool pmuv3_event_implemented(u16 event)
+{
+	bool ext = event >= ARMV8_PMUV3_EXT_COMMON_EVENT_BASE;
+	u16 id = ext ? event - ARMV8_PMUV3_EXT_COMMON_EVENT_BASE : event;
+	u64 pmceid;
+
+	if (id >= 64 || !pmuv3_implemented(read_pmuver()))
+		return false;
+
+	pmceid = id < 32 ? :() : read_pmceid1();
+	return pmceid & BIT_ULL(id % 32 + (ext ? 32 : 0));
+}
+
  static inline bool is_pmuv3p4(int pmuver)
  {
  	return pmuver >= ID_AA64DFR0_EL1_PMUVer_V3P4;
include/linux/perf/arm_pmu.h +0 -0
index 02d2c7f45b527..792283d29d7b5 100644

include/linux/perf/arm_pmu.h struct arm_pmu { · line 127

Quoted 5 lines
include/linux/perf/arm_pmu.h +0 -1
@@ -124,7 +124,6 @@ struct arm_pmu {
  	u64		reg_brbidr;
  #define ARMV8_PMUV3_MAX_COMMON_EVENTS		0x40
  	DECLARE_BITMAP(pmceid_bitmap, ARMV8_PMUV3_MAX_COMMON_EVENTS);
-#define ARMV8_PMUV3_EXT_COMMON_EVENT_BASE	0x4000
  	DECLARE_BITMAP(pmceid_ext_bitmap, ARMV8_PMUV3_MAX_COMMON_EVENTS);

Could we not avoid this change ? Or why not move both of the definitions ?

Also, I would need an ACK from the arm_pmu maintainers to accept this change via coresight tree.

Cheers
Suzuki

Quoted 16 lines
include/linux/perf/arm_pmu.h +0 -0
  	/* Only to be used by ACPI probing code */
include/linux/perf/arm_pmuv3.h +3 -0
index d698efba28a27..c21f185a283d6 100644
@@ -78,6 +78,9 @@
  #define ARMV8_PMUV3_PERFCTR_STALL_SLOT_FRONTEND			0x003E
  #define ARMV8_PMUV3_PERFCTR_STALL_SLOT				0x003F
 
+/* Base of the common events reported in PMCEID{0,1}[63:32] from PMUv3p1 */
+#define ARMV8_PMUV3_EXT_COMMON_EVENT_BASE			0x4000
+
  /* Statistical profiling extension microarchitectural events */
  #define ARMV8_SPE_PERFCTR_SAMPLE_POP				0x4000
  #define ARMV8_SPE_PERFCTR_SAMPLE_FEED				0x4001
reviewer
#54 lore raw

Re: [PATCH v4 5/7] perf: arm_pmuv3: Add pmuv3_event_implemented()

Quoted 56 lines · Suzuki K Poulose
Quoted 55 lines · Amir Ayupov

Drivers outside the PMU driver may need to know whether the local CPU's PMU implements a common event before relying on it, for example a trace unit driver checking that the PMU counts its external outputs as TRCEXTOUTn.

Add pmuv3_event_implemented() to the arm64 asm/arm_pmuv3.h, next to read_pmceid0() and read_pmceid1(). It reads PMCEID0/1 on the calling CPU:
events 0x0000-0x003f are reported in bits [31:0], and the common events from ARMV8_PMUV3_EXT_COMMON_EVENT_BASE in bits [63:32] from PMUv3p1. Move ARMV8_PMUV3_EXT_COMMON_EVENT_BASE next to the event numbers in linux/perf/arm_pmuv3.h so it is available without CONFIG_ARM_PMU.

Assisted-by Devmate:Opus-5.5

---
  arch/arm64/include/asm/arm_pmuv3.h | 19 +++++++++++++++++++ include/linux/perf/arm_pmu.h       |  1 - include/linux/perf/arm_pmuv3.h     |  3 +++

  3 files changed, 22 insertions(+), 1 deletion(-)
arch/arm64/include/asm/arm_pmuv3.h +3 -0
index 8a777dec8d88a..acd62c4f16743 100644
@@ -173,6 +173,25 @@ static inline bool pmuv3_implemented(int pmuver)
            pmuver == ID_AA64DFR0_EL1_PMUVer_NI);
   }
+/*
+ * Whether this CPU's PMU implements a common event, as reported by
+ * PMCEID{0,1}: events 0x0000-0x003f in bits [31:0], and from PMUv3p1 

events
+ * 0x4000-0x403f in bits [63:32], which read as zero before PMUv3p1.
+ * Must run on the CPU whose PMU is queried.
+ */

arch/arm64/include/asm/arm_pmuv3.h +13 -0
+static inline bool pmuv3_event_implemented(u16 event)
+{
+    bool ext = event >= ARMV8_PMUV3_EXT_COMMON_EVENT_BASE;
+    u16 id = ext ? event - ARMV8_PMUV3_EXT_COMMON_EVENT_BASE : event;
+    u64 pmceid;
+
+    if (id >= 64 || !pmuv3_implemented(read_pmuver()))
+        return false;
+
+    pmceid = id < 32 ? :() : read_pmceid1();
+    return pmceid & BIT_ULL(id % 32 + (ext ? 32 : 0));
+}
+

  static inline bool is_pmuv3p4(int pmuver) {
      return pmuver >= ID_AA64DFR0_EL1_PMUVer_V3P4;

include/linux/perf/arm_pmu.h +0 -0
index 02d2c7f45b527..792283d29d7b5 100644
Quoted 9 lines

include/linux/perf/arm_pmu.h struct arm_pmu { · line 127

Quoted 6 lines
include/linux/perf/arm_pmu.h +0 -1
@@ -124,7 +124,6 @@ struct arm_pmu {
       u64        reg_brbidr;
   #define ARMV8_PMUV3_MAX_COMMON_EVENTS        0x40
       DECLARE_BITMAP(pmceid_bitmap, ARMV8_PMUV3_MAX_COMMON_EVENTS);
-#define ARMV8_PMUV3_EXT_COMMON_EVENT_BASE    0x4000
       DECLARE_BITMAP(pmceid_ext_bitmap, ARMV8_PMUV3_MAX_COMMON_EVENTS);

Could we not avoid this change ? Or why not move both of the definitions ?

I don't think you can avoid it unless you redefine it. But the place it's moved to has similar event number definitions, so it seems ok to me.

Moving both makes sense though.

Quoted 24 lines

Also, I would need an ACK from the arm_pmu maintainers to accept this change via coresight tree.

Cheers
Suzuki

Quoted 15 lines
include/linux/perf/arm_pmu.h +0 -0
       /* Only to be used by ACPI probing code */
include/linux/perf/arm_pmuv3.h +1 -0
index d698efba28a27..c21f185a283d6 100644
@@ -78,6 +78,9 @@
   #define ARMV8_PMUV3_PERFCTR_STALL_SLOT_FRONTEND            0x003E
   #define ARMV8_PMUV3_PERFCTR_STALL_SLOT                0x003F
+/* Base of the common events reported in PMCEID{0,1}[63:32] from 

PMUv3p1 */

include/linux/perf/arm_pmuv3.h +2 -0
+#define ARMV8_PMUV3_EXT_COMMON_EVENT_BASE            0x4000
+

  /* Statistical profiling extension microarchitectural events */ #define ARMV8_SPE_PERFCTR_SAMPLE_POP                0x4000 #define ARMV8_SPE_PERFCTR_SAMPLE_FEED                0x4001

#55 lore raw

PATCH v4 6/7 coresight: etm4x: Report whether the PMU counts the external outputs

In reply to Amir Ayupov

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
---
 .../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(-)
drivers/hwtracing/coresight/coresight-config.h +2 -0
index 220bc54f8e5e1..4cf53230854d0 100644
@@ -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
drivers/hwtracing/coresight/coresight-etm4x-cfg.c +5 -1
index 52cb036bb04b9..9e4dc5950c13d 100644
@@ -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);
 }
drivers/hwtracing/coresight/coresight-etm4x-core.c +26 -0
index af017bd8a5477..cb5fbb0279b88 100644
@@ -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);
drivers/hwtracing/coresight/coresight-etm4x.h +3 -0
index 5417280cdb274..33994ad4b2641 100644
@@ -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.
  */
 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;
 };
 
 /**
drivers/hwtracing/coresight/coresight-syscfg-configfs.c +3 -0
index 2b40e556be872..7b3800138f625 100644
@@ -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;
 }
Signature · 1 line
2.52.0
#56 lore raw

Re: [PATCH v4 6/7] coresight: etm4x: Report whether the PMU counts the external outputs

Sashiko has reviewed this patch and found no issues.
Quoted 13 lines

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.

Quoted 7 lines

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

Sashiko has reviewed this patch and found no issues.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=6
reviewer Reviewed-by on v4 6/7
#57 lore raw

Re: [PATCH v4 6/7] coresight: etm4x: Report whether the PMU counts the external outputs

In reply to Amir Ayupov
Quoted 137 lines · Amir Ayupov

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
---
  .../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(-)
drivers/hwtracing/coresight/coresight-config.h +2 -0
index 220bc54f8e5e1..4cf53230854d0 100644
@@ -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
drivers/hwtracing/coresight/coresight-etm4x-cfg.c +5 -1
index 52cb036bb04b9..9e4dc5950c13d 100644
@@ -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);
  }
drivers/hwtracing/coresight/coresight-etm4x-core.c +26 -0
index af017bd8a5477..cb5fbb0279b88 100644
@@ -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);
drivers/hwtracing/coresight/coresight-etm4x.h +3 -0
index 5417280cdb274..33994ad4b2641 100644
@@ -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.
   */
  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;
  };
 
  /**
drivers/hwtracing/coresight/coresight-syscfg-configfs.c +0 -0
index 2b40e556be872..7b3800138f625 100644

drivers/hwtracing/coresight/coresight-syscfg-configfs.c static ssize_t cscfg_feat_matches_show(struct config_item *item, char *page) · line 258

Quoted 9 lines
drivers/hwtracing/coresight/coresight-syscfg-configfs.c +3 -0
@@ -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;
  }
maintainer
#58 lore raw

Re: [PATCH v4 6/7] coresight: etm4x: Report whether the PMU counts the external outputs

In reply to Amir Ayupov
Quoted 33 lines · Amir Ayupov

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
---
  .../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(-)
drivers/hwtracing/coresight/coresight-config.h +0 -0
index 220bc54f8e5e1..4cf53230854d0 100644

drivers/hwtracing/coresight/coresight-config.h line 43

Quoted 6 lines
drivers/hwtracing/coresight/coresight-config.h +2 -0
@@ -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 ?

Quoted 77 lines
drivers/hwtracing/coresight/coresight-config.h +0 -0
  /*
   * Limit number of presets in a configuration
drivers/hwtracing/coresight/coresight-etm4x-cfg.c +5 -1
index 52cb036bb04b9..9e4dc5950c13d 100644
@@ -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);
  }
drivers/hwtracing/coresight/coresight-etm4x-core.c +26 -0
index af017bd8a5477..cb5fbb0279b88 100644
@@ -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);
drivers/hwtracing/coresight/coresight-etm4x.h +0 -0
index 5417280cdb274..33994ad4b2641 100644

drivers/hwtracing/coresight/coresight-etm4x.h enum etm_impdef_type { · line 872

Quoted 5 lines
drivers/hwtracing/coresight/coresight-etm4x.h +2 -0
@@ -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

Quoted 25 lines
drivers/hwtracing/coresight/coresight-etm4x.h +1 -0
   */
  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;
  };
 
  /**
drivers/hwtracing/coresight/coresight-syscfg-configfs.c +3 -0
index 2b40e556be872..7b3800138f625 100644
@@ -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;
  }
#59 lore raw

PATCH v4 7/7 coresight: Add pmu_pulse/extout_pulse

In reply to Amir Ayupov

Add ETMv4 configuration 'pmu_pulse' with 'extout_pulse' feature which requires an ETE whose PMU counts its external outputs (CS_CFG_MATCH_CAP_TRCEXTOUT): event 1 selects the always-true resource and drives TRCEXTOUT1 PMU event which pulses on every cycle while the trace unit is enabled.

Assisted-by Devmate:Opus-5.5
---
 .../trace/coresight/coresight-config.rst      |  5 ++
 .../trace/coresight/coresight-perf.rst        | 15 +++++
 drivers/hwtracing/coresight/Makefile          |  1 +
 .../coresight/coresight-cfg-pmu-pulse.c       | 55 +++++++++++++++++++
 .../coresight/coresight-cfg-preload.c         |  2 +
 .../coresight/coresight-cfg-preload.h         |  2 +
 6 files changed, 80 insertions(+)
 create mode 100644 drivers/hwtracing/coresight/coresight-cfg-pmu-pulse.c
Documentation/trace/coresight/coresight-config.rst +5 -0
index 6d5ffa6f73471..3eed728bf0de1 100644
@@ -129,6 +129,11 @@ The following steps take place in the operation of a configuration.
 
 5) At the end of the perf session, the configuration will be disabled.
 
+The built-in 'pmu_pulse' configuration pulses ETM external output 1 for a PMU
+event to count. It only pulses while the ETM is enabled, so combined with AUX
+pause and resume the PMU event can time each trace window (see
+coresight-perf.rst).
+
 
 Viewing Configurations and Features
 ===================================
Documentation/trace/coresight/coresight-perf.rst +15 -0
index 0a77741a431ef..6770a455c6b59 100644
@@ -109,6 +109,21 @@ Example for triggering AUX pause and resume with PMU event::
         -e cycles/aux-action=pause,period=10000000/ \
         -e cycles/aux-action=resume,period=1050000/ -- sleep 1
 
+ETM-timed pause events
+~~~~~~~~~~~~~~~~~~~~~~
+
+The built-in ``pmu_pulse`` configuration pulses ETM external output 1 on every
+cycle of allowed trace, and a PMU event counting that output pauses trace after
+``N`` pulses, here 1000 cycles::
+
+  perf record -a -e cs_etm/pmu_pulse,aux-action=start-paused/u \
+    -e cycles/aux-action=resume,period=10000000/u \
+    -e trcextout1/aux-action=pause,period=1000/u \
+    -- sleep 1
+
+Each window is about ``N`` traced cycles plus the pause interrupt latency.
+The configuration only loads on an ETE whose PMU counts its external outputs.
+
 Perf test - Verify kernel and userspace perf CoreSight work
 -----------------------------------------------------------
 
drivers/hwtracing/coresight/Makefile +1 -0
index ab16d06783a57..568e797ac5a17 100644
@@ -28,6 +28,7 @@ obj-$(CONFIG_CORESIGHT) += coresight.o
 coresight-y := coresight-core.o  coresight-etm-perf.o coresight-platform.o \
 		coresight-sysfs.o coresight-syscfg.o coresight-config.o \
 		coresight-cfg-preload.o coresight-cfg-afdo.o coresight-cfg-pstop.o \
+		coresight-cfg-pmu-pulse.o \
 		coresight-syscfg-configfs.o coresight-trace-id.o
 obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o
 coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \
drivers/hwtracing/coresight/coresight-cfg-pmu-pulse.c new file +55 -0

55 lines not on this page · raw message

drivers/hwtracing/coresight/coresight-cfg-preload.c +2 -0
index 4980e68483c5b..a9a60a1c40845 100644
@@ -14,6 +14,7 @@ static struct cscfg_feature_desc *preload_feats[] = {
 #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
 	&strobe_etm4x,
 	&gen_etrig_etm4x,
+	&extout_pulse_etm4x,
 #endif
 	NULL
 };
@@ -22,6 +23,7 @@ static struct cscfg_config_desc *preload_cfgs[] = {
 #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
 	&afdo_etm4x,
 	&pstop_etm4x,
+	&pmu_pulse_etm4x,
 #endif
 	NULL
 };
drivers/hwtracing/coresight/coresight-cfg-preload.h +2 -0
index 291ba530a6a52..0058627f65ae5 100644
@@ -12,4 +12,6 @@ extern struct cscfg_feature_desc strobe_etm4x;
 extern struct cscfg_config_desc afdo_etm4x;
 extern struct cscfg_feature_desc gen_etrig_etm4x;
 extern struct cscfg_config_desc pstop_etm4x;
+extern struct cscfg_feature_desc extout_pulse_etm4x;
+extern struct cscfg_config_desc pmu_pulse_etm4x;
 #endif
Signature · 1 line
2.52.0
#60 lore raw

Re: [PATCH v4 7/7] coresight: Add pmu_pulse/extout_pulse

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] coresight: extout_pulse loads on ETE with single event lacking TRCEXTOUT1 --

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] coresight: extout_pulse loads on ETE with single event lacking TRCEXTOUT1 --

commit 5f7a0d60c7147cc2e10191888168dd0008749154
Author: Amir Ayupov <[email protected]>

coresight: Add pmu_pulse/extout_pulse

This commit adds the built-in pmu_pulse configuration and extout_pulse feature for ETMv4/ETE to pulse external output 1 on every traced cycle for the PMU to count as TRCEXTOUT1.

Quoted 6 lines
drivers/hwtracing/coresight/coresight-cfg-pmu-pulse.c new file +0 -0
new file mode 100644
index 0000000000000..61472154dd02a
@@ -0,0 +1,55 @@

[ ... ]

Quoted 8 lines
drivers/hwtracing/coresight/coresight-cfg-pmu-pulse.c new file +8 -0
+static struct cscfg_regval_desc extout_pulse_regs[] = {
+	/* event 1: resource selector 1 (always true), drives external output 1 */
+	{
+		.type = CS_CFG_REG_TYPE_STD | CS_CFG_REG_TYPE_VAL_MASK,
+		.offset = TRCEVENTCTL0R,
+		.val32 = 0x0100,
+		.mask32 = 0xff00,
+	},

drivers/hwtracing/coresight/coresight-cfg-pmu-pulse.c line 38

Quoted 10 lines
drivers/hwtracing/coresight/coresight-cfg-pmu-pulse.c new file +10 -0
+	/* end of regs */
+};
+
+struct cscfg_feature_desc extout_pulse_etm4x = {
+	.name = "extout_pulse",
+	.description = "Pulse external output 1 on every traced cycle.\n",
+	.match_flags = CS_CFG_MATCH_CLASS_SRC_ETM4 | CS_CFG_MATCH_CAP_TRCEXTOUT,
+	.nr_regs = ARRAY_SIZE(extout_pulse_regs),
+	.regs_desc = extout_pulse_regs,
+};

[Severity: Medium]
Can extout_pulse_etm4x load and enable on an ETE implementation that only supports a single event (event 0 / TRCEXTOUT0), where event 1 and TRCEXTOUT1 do not exist?

In drivers/hwtracing/coresight/coresight-etm4x-core.c, when TRCIDR0.NUMEVENT is 0 and resources are present, etm4_init_arch_data() sets caps->nr_event to
1. Then etm4_pmu_counts_extout() checks whether the implemented events have matching PMU counters:

drivers/hwtracing/coresight/coresight-etm4x-core.c:etm4_pmu_counts_extout() {
	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;
}

When drvdata->caps.nr_event == 1 and ARMV8_PMUV3_PERFCTR_TRCEXTOUT0 is implemented, etm4_pmu_counts_extout() returns true and etm4_cscfg_register() advertises CS_CFG_MATCH_CAP_TRCEXTOUT.

When loading the feature, etm4_cfg_load_feature() -> etm4_cfg_map_reg_offset() maps TRCEVENTCTL0R without checking whether drvdata->caps.nr_event >= 2. By contrast, event_store() in drivers/hwtracing/coresight/coresight-etm4x-sysfs.c shows that EVENT1 (bits [15:8] of TRCEVENTCTL0R) is only implemented when caps->nr_event >= 2:

	case 1:
		/* EVENT0, bits[7:0] */
		sysfs_config->eventctrl0 = val & 0xFF;
		break;
	case 2:
		/* EVENT1, bits[15:8] */
		sysfs_config->eventctrl0 = val & 0xFFFF;
		break;

On an ETE with caps.nr_event == 1, enabling pmu_pulse will succeed and write 0x0100 to the unimplemented EVENT1 field in TRCEVENTCTL0R while TRCEXTOUT1 does not exist. Should CS_CFG_MATCH_CAP_TRCEXTOUT or the feature loading path verify that event 1 (caps.nr_event >= 2 and TRCEXTOUT1) is available?

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=7
reviewer Reviewed-by on v4 7/7
#61 lore raw

Re: [PATCH v4 7/7] coresight: Add pmu_pulse/extout_pulse

In reply to Amir Ayupov
Quoted 159 lines · Amir Ayupov

Add ETMv4 configuration 'pmu_pulse' with 'extout_pulse' feature which requires an ETE whose PMU counts its external outputs (CS_CFG_MATCH_CAP_TRCEXTOUT): event 1 selects the always-true resource and drives TRCEXTOUT1 PMU event which pulses on every cycle while the trace unit is enabled.

Assisted-by Devmate:Opus-5.5
---
  .../trace/coresight/coresight-config.rst      |  5 ++
  .../trace/coresight/coresight-perf.rst        | 15 +++++
  drivers/hwtracing/coresight/Makefile          |  1 +
  .../coresight/coresight-cfg-pmu-pulse.c       | 55 +++++++++++++++++++
  .../coresight/coresight-cfg-preload.c         |  2 +
  .../coresight/coresight-cfg-preload.h         |  2 +
  6 files changed, 80 insertions(+)

create mode 100644 drivers/hwtracing/coresight/coresight-cfg-pmu-pulse.c

Documentation/trace/coresight/coresight-config.rst +5 -0
index 6d5ffa6f73471..3eed728bf0de1 100644
@@ -129,6 +129,11 @@ The following steps take place in the operation of a configuration.
 
  5) At the end of the perf session, the configuration will be disabled.
 
+The built-in 'pmu_pulse' configuration pulses ETM external output 1 for a PMU
+event to count. It only pulses while the ETM is enabled, so combined with AUX
+pause and resume the PMU event can time each trace window (see
+coresight-perf.rst).
+
 
  Viewing Configurations and Features
  ===================================
Documentation/trace/coresight/coresight-perf.rst +15 -0
index 0a77741a431ef..6770a455c6b59 100644
@@ -109,6 +109,21 @@ Example for triggering AUX pause and resume with PMU event::
          -e cycles/aux-action=pause,period=10000000/ \
          -e cycles/aux-action=resume,period=1050000/ -- sleep 1
 
+ETM-timed pause events
+~~~~~~~~~~~~~~~~~~~~~~
+
+The built-in ``pmu_pulse`` configuration pulses ETM external output 1 on every
+cycle of allowed trace, and a PMU event counting that output pauses trace after
+``N`` pulses, here 1000 cycles::
+
+  perf record -a -e cs_etm/pmu_pulse,aux-action=start-paused/u \
+    -e cycles/aux-action=resume,period=10000000/u \
+    -e trcextout1/aux-action=pause,period=1000/u \
+    -- sleep 1
+
+Each window is about ``N`` traced cycles plus the pause interrupt latency.
+The configuration only loads on an ETE whose PMU counts its external outputs.
+
  Perf test - Verify kernel and userspace perf CoreSight work
  -----------------------------------------------------------
 
drivers/hwtracing/coresight/Makefile +1 -0
index ab16d06783a57..568e797ac5a17 100644
@@ -28,6 +28,7 @@ obj-$(CONFIG_CORESIGHT) += coresight.o
  coresight-y := coresight-core.o  coresight-etm-perf.o coresight-platform.o \
  		coresight-sysfs.o coresight-syscfg.o coresight-config.o \
  		coresight-cfg-preload.o coresight-cfg-afdo.o coresight-cfg-pstop.o \
+		coresight-cfg-pmu-pulse.o \
  		coresight-syscfg-configfs.o coresight-trace-id.o
  obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o
  coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \
drivers/hwtracing/coresight/coresight-cfg-pmu-pulse.c new file +55 -0
new file mode 100644
index 0000000000000..61472154dd02a
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Pulse ETM external output 1 on every traced cycle for a PMU event to count.
+ * Based on coresight-cfg-afdo.c
+ */
+
+#include "coresight-config.h"
+
+/* ETMv4 includes and features */
+#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
+#include "coresight-etm4x-cfg.h"
+
+/*
+ * extout_pulse feature: event 1 selects the always-true resource, so ETM
+ * external output 1 pulses on every cycle while the trace unit is enabled. A
+ * PMU event counting that output (TRCEXTOUT1), for example with
+ * aux-action=pause, then fires after as many traced cycles as its sample
+ * period. Event 0 is avoided because it is the trace unit trigger, and the
+ * TRBE driver treats a detected trigger as fatal.
+ */
+static struct cscfg_regval_desc extout_pulse_regs[] = {
+	/* event 1: resource selector 1 (always true), drives external output 1 */
+	{
+		.type = CS_CFG_REG_TYPE_STD | CS_CFG_REG_TYPE_VAL_MASK,
+		.offset = TRCEVENTCTL0R,
+		.val32 = 0x0100,
+		.mask32 = 0xff00,
+	},
+	/* end of regs */
+};
+
+struct cscfg_feature_desc extout_pulse_etm4x = {
+	.name = "extout_pulse",
+	.description = "Pulse external output 1 on every traced cycle.\n",
+	.match_flags = CS_CFG_MATCH_CLASS_SRC_ETM4 | CS_CFG_MATCH_CAP_TRCEXTOUT,
+	.nr_regs = ARRAY_SIZE(extout_pulse_regs),
+	.regs_desc = extout_pulse_regs,
+};
+
+/* create a pmu_pulse configuration */
+
+static const char *pmu_pulse_ref_names[] = {
+	"extout_pulse",
+};
+
+struct cscfg_config_desc pmu_pulse_etm4x = {
+	.name = "pmu_pulse",
+	.description = "Pulse ETM external output 1 on every traced cycle for the PMU\n"
+	"to count as TRCEXTOUT1\n",
+	.nr_feat_refs = ARRAY_SIZE(pmu_pulse_ref_names),
+	.feat_ref_names = pmu_pulse_ref_names,
+};
+
+/* end of ETM4x configurations */
+#endif	/* IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X) */
drivers/hwtracing/coresight/coresight-cfg-preload.c +2 -0
index 4980e68483c5b..a9a60a1c40845 100644
@@ -14,6 +14,7 @@ static struct cscfg_feature_desc *preload_feats[] = {
  #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
  	&strobe_etm4x,
  	&gen_etrig_etm4x,
+	&extout_pulse_etm4x,
  #endif
  	NULL
  };
@@ -22,6 +23,7 @@ static struct cscfg_config_desc *preload_cfgs[] = {
  #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
  	&afdo_etm4x,
  	&pstop_etm4x,
+	&pmu_pulse_etm4x,
  #endif
  	NULL
  };
drivers/hwtracing/coresight/coresight-cfg-preload.h +0 -0
index 291ba530a6a52..0058627f65ae5 100644

drivers/hwtracing/coresight/coresight-cfg-preload.h extern struct cscfg_feature_desc strobe_etm4x; · line 17

Quoted 6 lines
drivers/hwtracing/coresight/coresight-cfg-preload.h +2 -0
@@ -12,4 +12,6 @@ extern struct cscfg_feature_desc strobe_etm4x;
  extern struct cscfg_config_desc afdo_etm4x;
  extern struct cscfg_feature_desc gen_etrig_etm4x;
  extern struct cscfg_config_desc pstop_etm4x;
+extern struct cscfg_feature_desc extout_pulse_etm4x;
+extern struct cscfg_config_desc pmu_pulse_etm4x;
  #endif
reviewer Tested-by on the v4 series
#62 lore raw
In reply to Amir Ayupov
Quoted 7 lines · Amir Ayupov

Add an ETMv4 configuration, pmu_pulse, that drives trace unit external output 1 on every traced cycle, so a PMU event counting it (TRCEXTOUT1) can end a fixed-length ETM window, for example with aux-action=pause. The feature only loads on an ETE whose PMU counts its external outputs.

Patch 1 is Leo's fix for TRCIDR0.NUMEVENT decoding, which patch 6 relies on for the number of external outputs.

Maybe it is worth to update patch 03 for Suzuki's comment:
https://lore.kernel.org/linux-arm-kernel/[email protected]/

This series looks good to me and I have verified it: