From 1164351241b52b3c8ffab4e29de5f93a9abe4acf Mon Sep 17 00:00:00 2001 From: Tuan Phan Date: Mon, 27 Apr 2020 13:41:56 -0700 Subject: [PATCH] perf/smmuv3: Allow sharing MMIO registers with the SMMU driver Some Arm SMMUv3 implementations, for example Arm CoreLink MMU-600, embed the PMCG registers into the SMMU MMIO regions. It currently causes probe failure because the PMU and SMMU drivers request overlapping resources. Avoid the conflict by calling devm_ioremap() directly from the PMU driver. We loose some sanity-checking of the memory map provided by firmware, which doesn't seem catastrophic. Backport from: https://lore.kernel.org/linux-arm-kernel/20200421155745.19815-1-jean-philippe@linaro.org/ Signed-off-by: Jean-Philippe Brucker Signed-off-by: Tuan Phan Signed-off-by: Tuan Phan --- drivers/iommu/arm-smmu-v3.c | 2 +- drivers/perf/arm_smmuv3_pmu.c | 25 +++++++++++++++++++------ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index fa8a400be..424564f7c 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -2854,7 +2854,7 @@ static int arm_smmu_device_probe(struct platform_device *pdev) } ioaddr = res->start; - smmu->base = devm_ioremap_resource(dev, res); + smmu->base = devm_ioremap(dev, res->start, resource_size(res)); if (IS_ERR(smmu->base)) return PTR_ERR(smmu->base); diff --git a/drivers/perf/arm_smmuv3_pmu.c b/drivers/perf/arm_smmuv3_pmu.c index a3dd7452e..518cf0b3e 100644 --- a/drivers/perf/arm_smmuv3_pmu.c +++ b/drivers/perf/arm_smmuv3_pmu.c @@ -723,19 +723,32 @@ static int smmu_pmu_probe(struct platform_device *pdev) .capabilities = PERF_PMU_CAP_NO_EXCLUDE, }; + /* + * If the PMCG registers are embedded into the SMMU regions, the + * resources have to be shared with the SMMU driver. Use ioremap() + * rather than ioremap_resource() to avoid conflicts. + */ res_0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); - smmu_pmu->reg_base = devm_ioremap_resource(dev, res_0); - if (IS_ERR(smmu_pmu->reg_base)) - return PTR_ERR(smmu_pmu->reg_base); + if (!res_0) + return -ENXIO; + + smmu_pmu->reg_base = devm_ioremap(dev, res_0->start, + resource_size(res_0)); + if (!smmu_pmu->reg_base) + return -ENOMEM; cfgr = readl_relaxed(smmu_pmu->reg_base + SMMU_PMCG_CFGR); /* Determine if page 1 is present */ if (cfgr & SMMU_PMCG_CFGR_RELOC_CTRS) { res_1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); - smmu_pmu->reloc_base = devm_ioremap_resource(dev, res_1); - if (IS_ERR(smmu_pmu->reloc_base)) - return PTR_ERR(smmu_pmu->reloc_base); + if (!res_1) + return -ENXIO; + + smmu_pmu->reloc_base = devm_ioremap(dev, res_1->start, + resource_size(res_1)); + if (!smmu_pmu->reloc_base) + return -ENOMEM; } else { smmu_pmu->reloc_base = smmu_pmu->reg_base; }