On 2021/1/20 23:54, Robin Murphy wrote: > On 2021-01-20 14:14, Leizhen (ThunderTown) wrote: >> >> >> On 2021/1/20 21:27, Robin Murphy wrote: >>> On 2021-01-20 09:26, Leizhen (ThunderTown) wrote: >>>> >>>> >>>> On 2021/1/20 11:37, Leizhen (ThunderTown) wrote: >>>>> >>>>> >>>>> On 2021/1/19 20:32, Robin Murphy wrote: >>>>>> On 2021-01-19 01:59, Zhen Lei wrote: >>>>>>> Some SMMUv3 implementation embed the Perf Monitor Group Registers (PMCG) >>>>>>> inside the first 64kB region of the SMMU. Since SMMU and PMCG are >>>>>>> managed >>>>>>> by two separate drivers, and this driver depends on ARM_SMMU_V3, so the >>>>>>> SMMU driver reserves the corresponding resource first, this driver >>>>>>> should >>>>>>> not reserve the corresponding resource again. Otherwise, a resource >>>>>>> reservation conflict is reported during boot. >>>>>>> >>>>>>> Signed-off-by: Zhen Lei <thunder.leiz...@huawei.com> >>>>>>> --- >>>>>>> drivers/perf/arm_smmuv3_pmu.c | 42 >>>>>>> ++++++++++++++++++++++++++++++++++++++++-- >>>>>>> 1 file changed, 40 insertions(+), 2 deletions(-) >>>>>>> >>>>>>> diff --git a/drivers/perf/arm_smmuv3_pmu.c >>>>>>> b/drivers/perf/arm_smmuv3_pmu.c >>>>>>> index 74474bb322c3f26..dcce085431c6ce8 100644 >>>>>>> --- a/drivers/perf/arm_smmuv3_pmu.c >>>>>>> +++ b/drivers/perf/arm_smmuv3_pmu.c >>>>>>> @@ -761,6 +761,44 @@ static void smmu_pmu_get_acpi_options(struct >>>>>>> smmu_pmu *smmu_pmu) >>>>>>> dev_notice(smmu_pmu->dev, "option mask 0x%x\n", >>>>>>> smmu_pmu->options); >>>>>>> } >>>>>>> +static void __iomem * >>>>>>> +smmu_pmu_get_and_ioremap_resource(struct platform_device *pdev, >>>>>>> + unsigned int index, >>>>>>> + struct resource **out_res) >>>>>>> +{ >>>>>>> + int ret; >>>>>>> + void __iomem *base; >>>>>>> + struct resource *res; >>>>>>> + >>>>>>> + res = platform_get_resource(pdev, IORESOURCE_MEM, index); >>>>>>> + if (!res) { >>>>>>> + dev_err(&pdev->dev, "invalid resource\n"); >>>>>>> + return IOMEM_ERR_PTR(-EINVAL); >>>>>>> + } >>>>>>> + if (out_res) >>>>>>> + *out_res = res; >>>>>>> + >>>>>>> + ret = region_intersects(res->start, resource_size(res), >>>>>>> + IORESOURCE_MEM, IORES_DESC_NONE); >>>>>>> + if (ret == REGION_INTERSECTS) { >>>>>>> + /* >>>>>>> + * The resource has already been reserved by the SMMUv3 driver. >>>>>>> + * Don't reserve it again, just do devm_ioremap(). >>>>>>> + */ >>>>>>> + base = devm_ioremap(&pdev->dev, res->start, >>>>>>> resource_size(res)); >>>>>>> + } else { >>>>>>> + /* >>>>>>> + * The resource may have not been reserved by any driver, or >>>>>>> + * has been reserved but not type IORESOURCE_MEM. In the latter >>>>>>> + * case, devm_ioremap_resource() reports a conflict and returns >>>>>>> + * IOMEM_ERR_PTR(-EBUSY). >>>>>>> + */ >>>>>>> + base = devm_ioremap_resource(&pdev->dev, res); >>>>>>> + } >>>>>> >>>>>> What if the PMCG driver simply happens to probe first? >>>>> >>>>> There are 4 cases: >>>>> 1) ARM_SMMU_V3=m, ARM_SMMU_V3_PMU=y >>>>> It's not allowed. Becase: ARM_SMMU_V3_PMU depends on ARM_SMMU_V3 >>>>> config ARM_SMMU_V3_PMU >>>>> tristate "ARM SMMUv3 Performance Monitors Extension" >>>>> depends on ARM64 && ACPI && ARM_SMMU_V3 >>>>> >>>>> 2) ARM_SMMU_V3=y, ARM_SMMU_V3_PMU=m >>>>> No problem, SMMUv3 will be initialized first. >>>>> >>>>> 3) ARM_SMMU_V3=y, ARM_SMMU_V3_PMU=y >>>>> vi drivers/Makefile >>>>> 60 obj-y += iommu/ >>>>> 172 obj-$(CONFIG_PERF_EVENTS) += perf/ >>>>> >>>>> This link sequence ensure that SMMUv3 driver will be initialized >>>>> first. >>>>> They are currently at the same initialization level. >>>>> >>>>> 4) ARM_SMMU_V3=m, ARM_SMMU_V3_PMU=m >>>>> Sorry, I thought module dependencies were generated based on >>>>> "depends on". >>>>> But I tried it today,module dependencies are generated only when >>>>> symbol >>>>> dependencies exist. I should use MODULE_SOFTDEP() to explicitly mark >>>>> the >>>>> dependency. I will send V2 later. >>>>> >>>> >>>> Hi Robin: >>>> I think I misunderstood your question. The probe() instead of >>>> module_init() >>>> determines the time for reserving register space resources. So we'd better >>>> reserve multiple small blocks of resources in SMMUv3 but perform ioremap() >>>> for >>>> the entire resource, if the probe() of the PMCG occurs first. >>>> I'll refine these patches to make both initialization sequences work >>>> well. >>>> I'm trying to send V2 this week. >>> >>> There's still the possibility that a PMCG is implemented in a root complex >>> or some other device that isn't an SMMU, so as I've said before, none of >>> this trickery really scales. >>> >>> As far as I understand it, the main point of reserving resources is to >>> catch bugs where things definitely should not be overlapping. PMCGs are by >>> definition part of some other device, so in general they *can* be expected >>> to overlap with whatever device that is. I still think it's most logical to >>> simply *not* try to reserve PMCG resources at all. >> >> If PMCG resources may overlap with other devices, that's really going to be >> a very tricky thing. OK, I'll follow your advice,just do ioremap() for the >> PMCG resources. >> >> I know that I/O resource information can be queried by running "cat >> /proc/iomem". If we do not reserve PMCG resources, should we provide an >> additional fs query interface? > > What would that be necessary for? The PMU devices are already named by base > address so they can be identified. Sysfs tells you whether the driver bound > to any platform devices or not (although in this case the existence of PMU > devices already makes that clear). /proc/iomem is for showing claimed > resources, and many drivers don't claim resources. I've never heard any > inkling of that being a practical problem :/ > OK, so keep the code of the PMCG driver unchanged. Currently, PMCG resources may not overlap with other devices except SMMUv3. I sometimes use "cat /proc/ioomem" to look up the base address, then use devmem command to query the register content. > Robin. > >>>>>>> + >>>>>>> + return base; >>>>>>> +} >>>>>>> + >>>>>>> static int smmu_pmu_probe(struct platform_device *pdev) >>>>>>> { >>>>>>> struct smmu_pmu *smmu_pmu; >>>>>>> @@ -793,7 +831,7 @@ static int smmu_pmu_probe(struct platform_device >>>>>>> *pdev) >>>>>>> .capabilities = PERF_PMU_CAP_NO_EXCLUDE, >>>>>>> }; >>>>>>> - smmu_pmu->reg_base = >>>>>>> devm_platform_get_and_ioremap_resource(pdev, 0, &res_0); >>>>>>> + smmu_pmu->reg_base = smmu_pmu_get_and_ioremap_resource(pdev, 0, >>>>>>> &res_0); >>>>>>> if (IS_ERR(smmu_pmu->reg_base)) >>>>>>> return PTR_ERR(smmu_pmu->reg_base); >>>>>>> @@ -801,7 +839,7 @@ static int smmu_pmu_probe(struct >>>>>>> platform_device *pdev) >>>>>>> /* Determine if page 1 is present */ >>>>>>> if (cfgr & SMMU_PMCG_CFGR_RELOC_CTRS) { >>>>>>> - smmu_pmu->reloc_base = devm_platform_ioremap_resource(pdev, 1); >>>>>>> + smmu_pmu->reloc_base = smmu_pmu_get_and_ioremap_resource(pdev, >>>>>>> 1, NULL); >>>>>>> if (IS_ERR(smmu_pmu->reloc_base)) >>>>>>> return PTR_ERR(smmu_pmu->reloc_base); >>>>>>> } else { >>>>>>> >>>>>> >>>>>> . >>>>>> >>>> >>> >>> . >>> >> > > . >