[PATCH] perf/arm-cmn: Stop claiming entire iomem region
Ilkka Koskinen
ilkka at os.amperecomputing.com
Mon Feb 23 19:39:37 PST 2026
Hi Robin,
On Thu, 19 Feb 2026, Robin Murphy wrote:
> So far, the PMU has been the only thing of interest in the vast mass
> of CMN registers, so we've gotten away with simply claiming the entire
> iomem region. However, now that we can support other features like MPAM
> controllers for the system caches, the PMU driver needs to stop being
> selfish and learn to share. Similarly to arm-ni, requesting just the
> DTC node(s) should suffice for staking our exclusive claim to the PMU
> features, as requesting hundreds of tiny regions for all the individual
> pmu_event_sel registers is definitely not worth the considerable bother.
Nice. It was on my list too but never really had time to work on. I was
actually wondering whether we should claim all the PMU regions but I agree
that would be a lot and pretty much pointless.
>
> As a consequence, we can also streamline the annoying CMN-600 special
> cases even more. The ACPI binding has in fact always specified a strict
> order for all resources, so we can reasonably drop the ancient pretence
> of swapping base and cfg, which IIRC was more just a moment of doubt on
> my part than anything else.
>
> Cc: James Morse <james.morse at arm.com>
> Signed-off-by: Robin Murphy <robin.murphy at arm.com>
Reviewed-by: Ilkka Koskinen <ilkka at os.amperecomputing.com>
Cheers, Ilkka
> ---
> drivers/perf/arm-cmn.c | 70 +++++++++++++++++++-----------------------
> 1 file changed, 31 insertions(+), 39 deletions(-)
>
> diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c
> index 364a4fd8f2c0..6a5eba0be347 100644
> --- a/drivers/perf/arm-cmn.c
> +++ b/drivers/perf/arm-cmn.c
> @@ -2132,6 +2132,8 @@ static void arm_cmn_init_dtm(struct arm_cmn_dtm *dtm, struct arm_cmn_node *xp, i
> static int arm_cmn_init_dtc(struct arm_cmn *cmn, struct arm_cmn_node *dn, int idx)
> {
> struct arm_cmn_dtc *dtc = cmn->dtc + idx;
> + const struct resource *cfg;
> + resource_size_t base, size;
>
> dtc->pmu_base = dn->pmu_base;
> dtc->base = dtc->pmu_base - arm_cmn_pmu_offset(cmn, dn);
> @@ -2139,6 +2141,13 @@ static int arm_cmn_init_dtc(struct arm_cmn *cmn, struct arm_cmn_node *dn, int id
> if (dtc->irq < 0)
> return dtc->irq;
>
> + cfg = platform_get_resource(to_platform_device(cmn->dev), IORESOURCE_MEM, 0);
> + base = dtc->base - cmn->base + cfg->start;
> + size = cmn->part == PART_CMN600 ? SZ_16K : SZ_64K;
> + if (!devm_request_mem_region(cmn->dev, base, size, dev_name(cmn->dev)))
> + return dev_err_probe(cmn->dev, -EBUSY,
> + "Failed to request DTC region 0x%llx\n", base);
> +
> writel_relaxed(CMN_DT_DTC_CTL_DT_EN, dtc->base + CMN_DT_DTC_CTL);
> writel_relaxed(CMN_DT_PMCR_PMU_EN | CMN_DT_PMCR_OVFL_INTR_EN, CMN_DT_PMCR(dtc));
> writeq_relaxed(0, CMN_DT_PMCCNTR(dtc));
> @@ -2525,43 +2534,26 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
> return 0;
> }
>
> -static int arm_cmn600_acpi_probe(struct platform_device *pdev, struct arm_cmn *cmn)
> -{
> - struct resource *cfg, *root;
> -
> - cfg = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> - if (!cfg)
> - return -EINVAL;
> -
> - root = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> - if (!root)
> - return -EINVAL;
> -
> - if (!resource_contains(cfg, root))
> - swap(cfg, root);
> - /*
> - * Note that devm_ioremap_resource() is dumb and won't let the platform
> - * device claim cfg when the ACPI companion device has already claimed
> - * root within it. But since they *are* already both claimed in the
> - * appropriate name, we don't really need to do it again here anyway.
> - */
> - cmn->base = devm_ioremap(cmn->dev, cfg->start, resource_size(cfg));
> - if (!cmn->base)
> - return -ENOMEM;
> -
> - return root->start - cfg->start;
> -}
> -
> -static int arm_cmn600_of_probe(struct device_node *np)
> +static int arm_cmn_get_root(struct arm_cmn *cmn, const struct resource *cfg)
> {
> + const struct device_node *np = cmn->dev->of_node;
> + const struct resource *root;
> u32 rootnode;
>
> - return of_property_read_u32(np, "arm,root-node", &rootnode) ?: rootnode;
> + if (cmn->part != PART_CMN600)
> + return 0;
> +
> + if (np)
> + return of_property_read_u32(np, "arm,root-node", &rootnode) ?: rootnode;
> +
> + root = platform_get_resource(to_platform_device(cmn->dev), IORESOURCE_MEM, 1);
> + return root ? root->start - cfg->start : -EINVAL;
> }
>
> static int arm_cmn_probe(struct platform_device *pdev)
> {
> struct arm_cmn *cmn;
> + const struct resource *cfg;
> const char *name;
> static atomic_t id;
> int err, rootnode, this_id;
> @@ -2575,16 +2567,16 @@ static int arm_cmn_probe(struct platform_device *pdev)
> cmn->cpu = cpumask_local_spread(0, dev_to_node(cmn->dev));
> platform_set_drvdata(pdev, cmn);
>
> - if (cmn->part == PART_CMN600 && has_acpi_companion(cmn->dev)) {
> - rootnode = arm_cmn600_acpi_probe(pdev, cmn);
> - } else {
> - rootnode = 0;
> - cmn->base = devm_platform_ioremap_resource(pdev, 0);
> - if (IS_ERR(cmn->base))
> - return PTR_ERR(cmn->base);
> - if (cmn->part == PART_CMN600)
> - rootnode = arm_cmn600_of_probe(pdev->dev.of_node);
> - }
> + cfg = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!cfg)
> + return -EINVAL;
> +
> + /* Map the whole region now, claim the DTCs once we've found them */
> + cmn->base = devm_ioremap(cmn->dev, cfg->start, resource_size(cfg));
> + if (IS_ERR(cmn->base))
> + return PTR_ERR(cmn->base);
> +
> + rootnode = arm_cmn_get_root(cmn, cfg);
> if (rootnode < 0)
> return rootnode;
>
> --
> 2.39.2.101.g768bb238c484.dirty
>
>
More information about the linux-arm-kernel
mailing list