Loading Documentation/devicetree/bindings/perf/arm,smmu-v3-pmcg.yaml 0 → 100644 +70 −0 Original line number Diff line number Diff line # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- $id: http://devicetree.org/schemas/perf/arm,smmu-v3-pmcg.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: Arm SMMUv3 Performance Monitor Counter Group maintainers: - Will Deacon <will@kernel.org> - Robin Murphy <robin.murphy@arm.com> description: | An SMMUv3 may have several Performance Monitor Counter Group (PMCG). They are standalone performance monitoring units that support both architected and IMPLEMENTATION DEFINED event counters. properties: $nodename: pattern: "^pmu@[0-9a-f]*" compatible: oneOf: - items: - const: arm,mmu-600-pmcg - const: arm,smmu-v3-pmcg - const: arm,smmu-v3-pmcg reg: items: - description: Register page 0 - description: Register page 1, if SMMU_PMCG_CFGR.RELOC_CTRS = 1 minItems: 1 interrupts: maxItems: 1 msi-parent: true required: - compatible - reg anyOf: - required: - interrupts - required: - msi-parent additionalProperties: false examples: - | #include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/interrupt-controller/irq.h> pmu@2b420000 { compatible = "arm,smmu-v3-pmcg"; reg = <0x2b420000 0x1000>, <0x2b430000 0x1000>; interrupts = <GIC_SPI 80 IRQ_TYPE_EDGE_RISING>; msi-parent = <&its 0xff0000>; }; pmu@2b440000 { compatible = "arm,smmu-v3-pmcg"; reg = <0x2b440000 0x1000>, <0x2b450000 0x1000>; interrupts = <GIC_SPI 81 IRQ_TYPE_EDGE_RISING>; msi-parent = <&its 0xff0000>; }; drivers/perf/arm_smmuv3_pmu.c +64 −2 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ #include <linux/kernel.h> #include <linux/list.h> #include <linux/msi.h> #include <linux/of.h> #include <linux/perf_event.h> #include <linux/platform_device.h> #include <linux/smp.h> Loading Loading @@ -75,6 +76,10 @@ #define SMMU_PMCG_CR 0xE04 #define SMMU_PMCG_CR_ENABLE BIT(0) #define SMMU_PMCG_IIDR 0xE08 #define SMMU_PMCG_IIDR_PRODUCTID GENMASK(31, 20) #define SMMU_PMCG_IIDR_VARIANT GENMASK(19, 16) #define SMMU_PMCG_IIDR_REVISION GENMASK(15, 12) #define SMMU_PMCG_IIDR_IMPLEMENTER GENMASK(11, 0) #define SMMU_PMCG_CEID0 0xE20 #define SMMU_PMCG_CEID1 0xE28 #define SMMU_PMCG_IRQ_CTRL 0xE50 Loading @@ -83,6 +88,20 @@ #define SMMU_PMCG_IRQ_CFG1 0xE60 #define SMMU_PMCG_IRQ_CFG2 0xE64 /* IMP-DEF ID registers */ #define SMMU_PMCG_PIDR0 0xFE0 #define SMMU_PMCG_PIDR0_PART_0 GENMASK(7, 0) #define SMMU_PMCG_PIDR1 0xFE4 #define SMMU_PMCG_PIDR1_DES_0 GENMASK(7, 4) #define SMMU_PMCG_PIDR1_PART_1 GENMASK(3, 0) #define SMMU_PMCG_PIDR2 0xFE8 #define SMMU_PMCG_PIDR2_REVISION GENMASK(7, 4) #define SMMU_PMCG_PIDR2_DES_1 GENMASK(2, 0) #define SMMU_PMCG_PIDR3 0xFEC #define SMMU_PMCG_PIDR3_REVAND GENMASK(7, 4) #define SMMU_PMCG_PIDR4 0xFD0 #define SMMU_PMCG_PIDR4_DES_2 GENMASK(3, 0) /* MSI config fields */ #define MSI_CFG0_ADDR_MASK GENMASK_ULL(51, 2) #define MSI_CFG2_MEMATTR_DEVICE_nGnRE 0x1 Loading Loading @@ -754,6 +773,41 @@ 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 bool smmu_pmu_coresight_id_regs(struct smmu_pmu *smmu_pmu) { return of_device_is_compatible(smmu_pmu->dev->of_node, "arm,mmu-600-pmcg"); } static void smmu_pmu_get_iidr(struct smmu_pmu *smmu_pmu) { u32 iidr = readl_relaxed(smmu_pmu->reg_base + SMMU_PMCG_IIDR); if (!iidr && smmu_pmu_coresight_id_regs(smmu_pmu)) { u32 pidr0 = readl(smmu_pmu->reg_base + SMMU_PMCG_PIDR0); u32 pidr1 = readl(smmu_pmu->reg_base + SMMU_PMCG_PIDR1); u32 pidr2 = readl(smmu_pmu->reg_base + SMMU_PMCG_PIDR2); u32 pidr3 = readl(smmu_pmu->reg_base + SMMU_PMCG_PIDR3); u32 pidr4 = readl(smmu_pmu->reg_base + SMMU_PMCG_PIDR4); u32 productid = FIELD_GET(SMMU_PMCG_PIDR0_PART_0, pidr0) | (FIELD_GET(SMMU_PMCG_PIDR1_PART_1, pidr1) << 8); u32 variant = FIELD_GET(SMMU_PMCG_PIDR2_REVISION, pidr2); u32 revision = FIELD_GET(SMMU_PMCG_PIDR3_REVAND, pidr3); u32 implementer = FIELD_GET(SMMU_PMCG_PIDR1_DES_0, pidr1) | (FIELD_GET(SMMU_PMCG_PIDR2_DES_1, pidr2) << 4) | (FIELD_GET(SMMU_PMCG_PIDR4_DES_2, pidr4) << 8); iidr = FIELD_PREP(SMMU_PMCG_IIDR_PRODUCTID, productid) | FIELD_PREP(SMMU_PMCG_IIDR_VARIANT, variant) | FIELD_PREP(SMMU_PMCG_IIDR_REVISION, revision) | FIELD_PREP(SMMU_PMCG_IIDR_IMPLEMENTER, implementer); } smmu_pmu->iidr = iidr; } static int smmu_pmu_probe(struct platform_device *pdev) { struct smmu_pmu *smmu_pmu; Loading Loading @@ -825,7 +879,7 @@ static int smmu_pmu_probe(struct platform_device *pdev) return err; } smmu_pmu->iidr = readl_relaxed(smmu_pmu->reg_base + SMMU_PMCG_IIDR); smmu_pmu_get_iidr(smmu_pmu); name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "smmuv3_pmcg_%llx", (res_0->start) >> SMMU_PMCG_PA_SHIFT); Loading @@ -834,6 +888,7 @@ static int smmu_pmu_probe(struct platform_device *pdev) return -EINVAL; } if (!dev->of_node) smmu_pmu_get_acpi_options(smmu_pmu); /* Pick one CPU to be the preferred one to use */ Loading Loading @@ -884,9 +939,16 @@ static void smmu_pmu_shutdown(struct platform_device *pdev) smmu_pmu_disable(&smmu_pmu->pmu); } static const struct of_device_id smmu_pmu_of_match[] = { { .compatible = "arm,smmu-v3-pmcg" }, {} }; MODULE_DEVICE_TABLE(of, smmu_pmu_of_match); static struct platform_driver smmu_pmu_driver = { .driver = { .name = "arm-smmu-v3-pmcg", .of_match_table = of_match_ptr(smmu_pmu_of_match), .suppress_bind_attrs = true, }, .probe = smmu_pmu_probe, Loading Loading
Documentation/devicetree/bindings/perf/arm,smmu-v3-pmcg.yaml 0 → 100644 +70 −0 Original line number Diff line number Diff line # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- $id: http://devicetree.org/schemas/perf/arm,smmu-v3-pmcg.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: Arm SMMUv3 Performance Monitor Counter Group maintainers: - Will Deacon <will@kernel.org> - Robin Murphy <robin.murphy@arm.com> description: | An SMMUv3 may have several Performance Monitor Counter Group (PMCG). They are standalone performance monitoring units that support both architected and IMPLEMENTATION DEFINED event counters. properties: $nodename: pattern: "^pmu@[0-9a-f]*" compatible: oneOf: - items: - const: arm,mmu-600-pmcg - const: arm,smmu-v3-pmcg - const: arm,smmu-v3-pmcg reg: items: - description: Register page 0 - description: Register page 1, if SMMU_PMCG_CFGR.RELOC_CTRS = 1 minItems: 1 interrupts: maxItems: 1 msi-parent: true required: - compatible - reg anyOf: - required: - interrupts - required: - msi-parent additionalProperties: false examples: - | #include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/interrupt-controller/irq.h> pmu@2b420000 { compatible = "arm,smmu-v3-pmcg"; reg = <0x2b420000 0x1000>, <0x2b430000 0x1000>; interrupts = <GIC_SPI 80 IRQ_TYPE_EDGE_RISING>; msi-parent = <&its 0xff0000>; }; pmu@2b440000 { compatible = "arm,smmu-v3-pmcg"; reg = <0x2b440000 0x1000>, <0x2b450000 0x1000>; interrupts = <GIC_SPI 81 IRQ_TYPE_EDGE_RISING>; msi-parent = <&its 0xff0000>; };
drivers/perf/arm_smmuv3_pmu.c +64 −2 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ #include <linux/kernel.h> #include <linux/list.h> #include <linux/msi.h> #include <linux/of.h> #include <linux/perf_event.h> #include <linux/platform_device.h> #include <linux/smp.h> Loading Loading @@ -75,6 +76,10 @@ #define SMMU_PMCG_CR 0xE04 #define SMMU_PMCG_CR_ENABLE BIT(0) #define SMMU_PMCG_IIDR 0xE08 #define SMMU_PMCG_IIDR_PRODUCTID GENMASK(31, 20) #define SMMU_PMCG_IIDR_VARIANT GENMASK(19, 16) #define SMMU_PMCG_IIDR_REVISION GENMASK(15, 12) #define SMMU_PMCG_IIDR_IMPLEMENTER GENMASK(11, 0) #define SMMU_PMCG_CEID0 0xE20 #define SMMU_PMCG_CEID1 0xE28 #define SMMU_PMCG_IRQ_CTRL 0xE50 Loading @@ -83,6 +88,20 @@ #define SMMU_PMCG_IRQ_CFG1 0xE60 #define SMMU_PMCG_IRQ_CFG2 0xE64 /* IMP-DEF ID registers */ #define SMMU_PMCG_PIDR0 0xFE0 #define SMMU_PMCG_PIDR0_PART_0 GENMASK(7, 0) #define SMMU_PMCG_PIDR1 0xFE4 #define SMMU_PMCG_PIDR1_DES_0 GENMASK(7, 4) #define SMMU_PMCG_PIDR1_PART_1 GENMASK(3, 0) #define SMMU_PMCG_PIDR2 0xFE8 #define SMMU_PMCG_PIDR2_REVISION GENMASK(7, 4) #define SMMU_PMCG_PIDR2_DES_1 GENMASK(2, 0) #define SMMU_PMCG_PIDR3 0xFEC #define SMMU_PMCG_PIDR3_REVAND GENMASK(7, 4) #define SMMU_PMCG_PIDR4 0xFD0 #define SMMU_PMCG_PIDR4_DES_2 GENMASK(3, 0) /* MSI config fields */ #define MSI_CFG0_ADDR_MASK GENMASK_ULL(51, 2) #define MSI_CFG2_MEMATTR_DEVICE_nGnRE 0x1 Loading Loading @@ -754,6 +773,41 @@ 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 bool smmu_pmu_coresight_id_regs(struct smmu_pmu *smmu_pmu) { return of_device_is_compatible(smmu_pmu->dev->of_node, "arm,mmu-600-pmcg"); } static void smmu_pmu_get_iidr(struct smmu_pmu *smmu_pmu) { u32 iidr = readl_relaxed(smmu_pmu->reg_base + SMMU_PMCG_IIDR); if (!iidr && smmu_pmu_coresight_id_regs(smmu_pmu)) { u32 pidr0 = readl(smmu_pmu->reg_base + SMMU_PMCG_PIDR0); u32 pidr1 = readl(smmu_pmu->reg_base + SMMU_PMCG_PIDR1); u32 pidr2 = readl(smmu_pmu->reg_base + SMMU_PMCG_PIDR2); u32 pidr3 = readl(smmu_pmu->reg_base + SMMU_PMCG_PIDR3); u32 pidr4 = readl(smmu_pmu->reg_base + SMMU_PMCG_PIDR4); u32 productid = FIELD_GET(SMMU_PMCG_PIDR0_PART_0, pidr0) | (FIELD_GET(SMMU_PMCG_PIDR1_PART_1, pidr1) << 8); u32 variant = FIELD_GET(SMMU_PMCG_PIDR2_REVISION, pidr2); u32 revision = FIELD_GET(SMMU_PMCG_PIDR3_REVAND, pidr3); u32 implementer = FIELD_GET(SMMU_PMCG_PIDR1_DES_0, pidr1) | (FIELD_GET(SMMU_PMCG_PIDR2_DES_1, pidr2) << 4) | (FIELD_GET(SMMU_PMCG_PIDR4_DES_2, pidr4) << 8); iidr = FIELD_PREP(SMMU_PMCG_IIDR_PRODUCTID, productid) | FIELD_PREP(SMMU_PMCG_IIDR_VARIANT, variant) | FIELD_PREP(SMMU_PMCG_IIDR_REVISION, revision) | FIELD_PREP(SMMU_PMCG_IIDR_IMPLEMENTER, implementer); } smmu_pmu->iidr = iidr; } static int smmu_pmu_probe(struct platform_device *pdev) { struct smmu_pmu *smmu_pmu; Loading Loading @@ -825,7 +879,7 @@ static int smmu_pmu_probe(struct platform_device *pdev) return err; } smmu_pmu->iidr = readl_relaxed(smmu_pmu->reg_base + SMMU_PMCG_IIDR); smmu_pmu_get_iidr(smmu_pmu); name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "smmuv3_pmcg_%llx", (res_0->start) >> SMMU_PMCG_PA_SHIFT); Loading @@ -834,6 +888,7 @@ static int smmu_pmu_probe(struct platform_device *pdev) return -EINVAL; } if (!dev->of_node) smmu_pmu_get_acpi_options(smmu_pmu); /* Pick one CPU to be the preferred one to use */ Loading Loading @@ -884,9 +939,16 @@ static void smmu_pmu_shutdown(struct platform_device *pdev) smmu_pmu_disable(&smmu_pmu->pmu); } static const struct of_device_id smmu_pmu_of_match[] = { { .compatible = "arm,smmu-v3-pmcg" }, {} }; MODULE_DEVICE_TABLE(of, smmu_pmu_of_match); static struct platform_driver smmu_pmu_driver = { .driver = { .name = "arm-smmu-v3-pmcg", .of_match_table = of_match_ptr(smmu_pmu_of_match), .suppress_bind_attrs = true, }, .probe = smmu_pmu_probe, Loading