]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
perf/arm-cmn: Stop claiming entire iomem region
authorRobin Murphy <robin.murphy@arm.com>
Thu, 19 Feb 2026 17:27:53 +0000 (17:27 +0000)
committerWill Deacon <will@kernel.org>
Tue, 24 Mar 2026 12:34:38 +0000 (12:34 +0000)
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.

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@arm.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Tested-by: Ben Horgan <ben.horgan@arm.com>
Reviewed-by: Ilkka Koskinen <ilkka@os.amperecomputing.com>
Signed-off-by: Will Deacon <will@kernel.org>
drivers/perf/arm-cmn.c

index 40c05c519a1d9ff4eac884461008c547261f050d..1ac91cda678019f8c21fd95dabf71b1f9f91bc20 100644 (file)
@@ -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)
+static int arm_cmn_get_root(struct arm_cmn *cmn, const struct resource *cfg)
 {
-       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;
+       const struct device_node *np = cmn->dev->of_node;
+       const struct resource *root;
+       u32 rootnode;
 
-       return root->start - cfg->start;
-}
+       if (cmn->part != PART_CMN600)
+               return 0;
 
-static int arm_cmn600_of_probe(struct device_node *np)
-{
-       u32 rootnode;
+       if (np)
+               return of_property_read_u32(np, "arm,root-node", &rootnode) ?: rootnode;
 
-       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;