[PATCH v3 1/2] perf: arm_pmu: Accept a per-device CPU mask from platform data

Johnny.Fan johnny.fan at cixtech.com
Mon Nov 2 00:41:51 PST 2026


From: "Johnny.Fan" <Johnny.Fan at cixtech.com>

Synthetic platform devices created from ACPI data have no fwnode, so
platform_get_irq_affinity() cannot tell which CPUs implement the
feature and falls back to cpu_possible_mask.

Add an optional CPU mask to the platform data and make both the SPE and
the TRBE drivers prefer it over the firmware-described IRQ affinity.
Device tree devices have no platform data and keep using the affinity.

TRBE must also pass a stable copy of the mask to
request_percpu_irq_affinity(), because supported_cpus is pruned as CPUs
are probed, while the IRQ action keeps a pointer to the mask.

This is a preparatory change: no ACPI device carries platform data yet,
so behaviour is unchanged.

Signed-off-by: Johnny.Fan <Johnny.Fan at cixtech.com>
Reviewed-by: Fugang Duan <fugang.duan at cixtech.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 22 +++++++++++++++++---
 drivers/perf/arm_spe_pmu.c                   | 10 ++++++++-
 include/linux/perf/arm_pmu.h                 | 10 +++++++++
 3 files changed, 38 insertions(+), 4 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index c7cbca45f2de..0c4bc8fbcaf3 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -158,6 +158,7 @@ struct trbe_drvdata {
 	struct hlist_node hotplug_node;
 	int irq;
 	cpumask_t supported_cpus;
+	cpumask_t irq_affinity;
 	enum cpuhp_state trbe_online;
 	struct platform_device *pdev;
 };
@@ -1533,6 +1534,8 @@ static void arm_trbe_remove_cpuhp(struct trbe_drvdata *drvdata)
 static int arm_trbe_probe_irq(struct platform_device *pdev,
 			      struct trbe_drvdata *drvdata)
 {
+	const struct arm_pmu_acpi_dev_data *acpi_data =
+		dev_get_platdata(&pdev->dev);
 	const struct cpumask *affinity;
 	int ret;
 
@@ -1547,14 +1550,27 @@ static int arm_trbe_probe_irq(struct platform_device *pdev,
 		return -EINVAL;
 	}
 
-	cpumask_copy(&drvdata->supported_cpus, affinity);
+	/*
+	 * The ACPI path has no fwnode describing which CPUs implement TRBE,
+	 * so it passes the mask explicitly. DT devices still use the
+	 * firmware-described IRQ affinity.
+	 */
+	cpumask_copy(&drvdata->supported_cpus,
+		     acpi_data ? &acpi_data->cpus : affinity);
+
+	/*
+	 * supported_cpus gets pruned as CPUs are probed, so keep a stable
+	 * copy for the IRQ action.
+	 */
+	cpumask_copy(&drvdata->irq_affinity, &drvdata->supported_cpus);
 
 	drvdata->handle = alloc_percpu(struct perf_output_handle *);
 	if (!drvdata->handle)
 		return -ENOMEM;
 
-	ret = request_percpu_irq_affinity(drvdata->irq, arm_trbe_irq_handler, DRVNAME,
-					  affinity, drvdata->handle);
+	ret = request_percpu_irq_affinity(drvdata->irq, arm_trbe_irq_handler,
+					  DRVNAME, &drvdata->irq_affinity,
+					  drvdata->handle);
 	if (ret) {
 		free_percpu(drvdata->handle);
 		return ret;
diff --git a/drivers/perf/arm_spe_pmu.c b/drivers/perf/arm_spe_pmu.c
index b70f3fedf028..712b7f187301 100644
--- a/drivers/perf/arm_spe_pmu.c
+++ b/drivers/perf/arm_spe_pmu.c
@@ -1330,6 +1330,8 @@ static void arm_spe_pmu_dev_teardown(struct arm_spe_pmu *spe_pmu)
 static int arm_spe_pmu_irq_probe(struct arm_spe_pmu *spe_pmu)
 {
 	struct platform_device *pdev = spe_pmu->pdev;
+	const struct arm_pmu_acpi_dev_data *acpi_data =
+		dev_get_platdata(&pdev->dev);
 	const struct cpumask *affinity;
 	int irq;
 
@@ -1342,7 +1344,13 @@ static int arm_spe_pmu_irq_probe(struct arm_spe_pmu *spe_pmu)
 		return -EINVAL;
 	}
 
-	cpumask_copy(&spe_pmu->supported_cpus, affinity);
+	/*
+	 * The ACPI path has no fwnode describing which CPUs implement SPE,
+	 * so it passes the mask explicitly. DT devices still use the
+	 * firmware-described IRQ affinity.
+	 */
+	cpumask_copy(&spe_pmu->supported_cpus,
+		     acpi_data ? &acpi_data->cpus : affinity);
 
 	spe_pmu->irq = irq;
 	return 0;
diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h
index 02d2c7f45b52..7f1c03c55025 100644
--- a/include/linux/perf/arm_pmu.h
+++ b/include/linux/perf/arm_pmu.h
@@ -8,6 +8,7 @@
 #ifndef __ARM_PMU_H__
 #define __ARM_PMU_H__
 
+#include <linux/cpumask.h>
 #include <linux/interrupt.h>
 #include <linux/perf_event.h>
 #include <linux/platform_device.h>
@@ -199,6 +200,15 @@ void armpmu_free_irq(struct arm_pmu * __percpu *armpmu, int irq, int cpu);
 #define ARMV8_SPE_PDEV_NAME "arm,spe-v1"
 #define ARMV8_TRBE_PDEV_NAME "arm,trbe"
 
+/*
+ * Per-device CPU mask passed by the ACPI MADT walk. The synthetic
+ * platform devices have no fwnode, so the IRQ affinity cannot describe
+ * which CPUs actually implement the feature.
+ */
+struct arm_pmu_acpi_dev_data {
+	struct cpumask cpus;
+};
+
 /* Why does everything I do descend into this? */
 #define __GEN_PMU_FORMAT_ATTR(cfg, lo, hi)				\
 	(lo) == (hi) ? #cfg ":" #lo "\n" : #cfg ":" #lo "-" #hi
-- 
2.55.0




More information about the linux-arm-kernel mailing list