[PATCH 4/4] perf/arm-cmn: Convert to PERF_PMU_SCOPE_DEVICE
Haris Okanovic
harisokn at amazon.com
Tue Oct 13 11:56:03 PDT 2026
Set pmu::scope to PERF_PMU_SCOPE_DEVICE and remove the driver-tracked cpu,
hotplug hooks, and the 'cpumask' attribute, since perf core does this
for device scope PMUs.
Define a filter_allowed_cpus() callback to keep preference for CPUs local
to the interconnect's NUMA node, and a migrate_cpu() callback to update
DTC interrupt affinity on migration.
Signed-off-by: Haris Okanovic <harisokn at amazon.com>
---
drivers/perf/arm-cmn.c | 104 +++++++++--------------------------------
1 file changed, 22 insertions(+), 82 deletions(-)
diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c
index 5378fba916cf5..997ee5adf3f8e 100644
--- a/drivers/perf/arm-cmn.c
+++ b/drivers/perf/arm-cmn.c
@@ -388,17 +388,12 @@ struct arm_cmn {
struct arm_cmn_dtc *dtc;
unsigned int num_dtcs;
- int cpu;
- struct hlist_node cpuhp_node;
-
struct pmu pmu;
struct dentry *debug;
};
#define to_cmn(p) container_of(p, struct arm_cmn, pmu)
-static int arm_cmn_hp_state;
-
struct arm_cmn_nodeid {
u8 port;
u8 dev;
@@ -1511,17 +1506,6 @@ static const struct attribute_group arm_cmn_format_attrs_group = {
.attrs = arm_cmn_format_attrs,
};
-static ssize_t arm_cmn_cpumask_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct arm_cmn *cmn = to_cmn(dev_get_drvdata(dev));
-
- return sysfs_emit(buf, "%*pbl\n", cpumask_pr_args(cpumask_of(cmn->cpu)));
-}
-
-static struct device_attribute arm_cmn_cpumask_attr =
- __ATTR(cpumask, 0444, arm_cmn_cpumask_show, NULL);
-
static ssize_t arm_cmn_identifier_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -1534,7 +1518,6 @@ static struct device_attribute arm_cmn_identifier_attr =
__ATTR(identifier, 0444, arm_cmn_identifier_show, NULL);
static struct attribute *arm_cmn_other_attrs[] = {
- &arm_cmn_cpumask_attr.attr,
&arm_cmn_identifier_attr.attr,
NULL,
};
@@ -1981,11 +1964,7 @@ static int arm_cmn_event_init(struct perf_event *event)
if (event->attr.type != event->pmu->type)
return -ENOENT;
- if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
- return -EINVAL;
-
- event->cpu = cmn->cpu;
- if (event->cpu < 0)
+ if (is_sampling_event(event))
return -EINVAL;
type = CMN_EVENT_TYPE(event);
@@ -2243,48 +2222,26 @@ static int arm_cmn_commit_txn(struct pmu *pmu)
return 0;
}
-static void arm_cmn_migrate(struct arm_cmn *cmn, unsigned int cpu)
+static int arm_cmn_filter_allowed_cpus(struct pmu *pmu, struct cpumask *allowed_cpus)
{
- unsigned int i;
+ struct arm_cmn *cmn = to_cmn(pmu);
+ int node = dev_to_node(cmn->dev);
- perf_pmu_migrate_context(&cmn->pmu, cmn->cpu, cpu);
- for (i = 0; i < cmn->num_dtcs; i++)
- irq_set_affinity(cmn->dtc[i].irq, cpumask_of(cpu));
- cmn->cpu = cpu;
-}
+ /* Any CPU can drive the CMN, but prefer local ones */
+ if (node != NUMA_NO_NODE &&
+ cpumask_intersects(allowed_cpus, cpumask_of_node(node)))
+ cpumask_and(allowed_cpus, allowed_cpus, cpumask_of_node(node));
-static int arm_cmn_pmu_online_cpu(unsigned int cpu, struct hlist_node *cpuhp_node)
-{
- struct arm_cmn *cmn;
- int node;
-
- cmn = hlist_entry_safe(cpuhp_node, struct arm_cmn, cpuhp_node);
- node = dev_to_node(cmn->dev);
- if (cpu_to_node(cmn->cpu) != node && cpu_to_node(cpu) == node)
- arm_cmn_migrate(cmn, cpu);
- return 0;
+ return cpumask_empty(allowed_cpus) ? -ENODEV : 0;
}
-static int arm_cmn_pmu_offline_cpu(unsigned int cpu, struct hlist_node *cpuhp_node)
+static void arm_cmn_migrate_cpu(struct pmu *pmu, unsigned int cpu)
{
- struct arm_cmn *cmn;
- unsigned int target;
- int node;
-
- cmn = hlist_entry_safe(cpuhp_node, struct arm_cmn, cpuhp_node);
- if (cpu != cmn->cpu)
- return 0;
-
- node = dev_to_node(cmn->dev);
-
- target = cpumask_any_and_but(cpumask_of_node(node), cpu_online_mask, cpu);
- if (target >= nr_cpu_ids)
- target = cpumask_any_but(cpu_online_mask, cpu);
-
- if (target < nr_cpu_ids)
- arm_cmn_migrate(cmn, target);
+ struct arm_cmn *cmn = to_cmn(pmu);
+ unsigned int i;
- return 0;
+ for (i = 0; i < cmn->num_dtcs; i++)
+ WARN_ON_ONCE(irq_set_affinity(cmn->dtc[i].irq, cpumask_of(cpu)));
}
static irqreturn_t arm_cmn_handle_irq(int irq, void *dev_id)
@@ -2341,10 +2298,6 @@ static int arm_cmn_init_irqs(struct arm_cmn *cmn)
dev_name(cmn->dev), &cmn->dtc[i]);
if (err)
return err;
-
- err = irq_set_affinity(irq, cpumask_of(cmn->cpu));
- if (err)
- return err;
next:
; /* isn't C great? */
}
@@ -2843,7 +2796,6 @@ static int arm_cmn_probe(struct platform_device *pdev)
cmn->dev = &pdev->dev;
cmn->part = (unsigned long)device_get_match_data(cmn->dev);
- cmn->cpu = cpumask_local_spread(0, dev_to_node(cmn->dev));
platform_set_drvdata(pdev, cmn);
cfg = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -2877,6 +2829,7 @@ static int arm_cmn_probe(struct platform_device *pdev)
.attr_groups = arm_cmn_attr_groups,
.capabilities = PERF_PMU_CAP_NO_EXCLUDE,
.task_ctx_nr = perf_invalid_context,
+ .scope = PERF_PMU_SCOPE_DEVICE,
.pmu_enable = arm_cmn_pmu_enable,
.pmu_disable = arm_cmn_pmu_disable,
.event_init = arm_cmn_event_init,
@@ -2888,6 +2841,8 @@ static int arm_cmn_probe(struct platform_device *pdev)
.start_txn = arm_cmn_start_txn,
.commit_txn = arm_cmn_commit_txn,
.cancel_txn = arm_cmn_end_txn,
+ .filter_allowed_cpus = arm_cmn_filter_allowed_cpus,
+ .migrate_cpu = arm_cmn_migrate_cpu,
};
this_id = atomic_fetch_inc(&id);
@@ -2895,17 +2850,13 @@ static int arm_cmn_probe(struct platform_device *pdev)
if (!name)
return -ENOMEM;
- err = cpuhp_state_add_instance(arm_cmn_hp_state, &cmn->cpuhp_node);
+ err = perf_pmu_register(&cmn->pmu, name, -1);
if (err)
return err;
- err = perf_pmu_register(&cmn->pmu, name, -1);
- if (err)
- cpuhp_state_remove_instance_nocalls(arm_cmn_hp_state, &cmn->cpuhp_node);
- else
- arm_cmn_debugfs_init(cmn, this_id);
+ arm_cmn_debugfs_init(cmn, this_id);
- return err;
+ return 0;
}
static void arm_cmn_remove(struct platform_device *pdev)
@@ -2915,7 +2866,6 @@ static void arm_cmn_remove(struct platform_device *pdev)
writel_relaxed(0, cmn->dtc[0].base + CMN_DT_DTC_CTL);
perf_pmu_unregister(&cmn->pmu);
- cpuhp_state_remove_instance_nocalls(arm_cmn_hp_state, &cmn->cpuhp_node);
debugfs_remove(cmn->debug);
}
@@ -2958,28 +2908,18 @@ static int __init arm_cmn_init(void)
{
int ret;
- ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
- "perf/arm/cmn:online",
- arm_cmn_pmu_online_cpu,
- arm_cmn_pmu_offline_cpu);
- if (ret < 0)
- return ret;
-
- arm_cmn_hp_state = ret;
arm_cmn_debugfs = debugfs_create_dir("arm-cmn", NULL);
ret = platform_driver_register(&arm_cmn_driver);
- if (ret) {
- cpuhp_remove_multi_state(arm_cmn_hp_state);
+ if (ret)
debugfs_remove(arm_cmn_debugfs);
- }
+
return ret;
}
static void __exit arm_cmn_exit(void)
{
platform_driver_unregister(&arm_cmn_driver);
- cpuhp_remove_multi_state(arm_cmn_hp_state);
debugfs_remove(arm_cmn_debugfs);
}
--
Haris Okanovic
AWS Graviton
More information about the linux-arm-kernel
mailing list