Commit 1879a61f authored by Will Deacon's avatar Will Deacon
Browse files

Merge branch 'for-next/perf-smmu' into for-next/perf

* for-next/perf-smmu:
  perf/smmuv3: Synthesize IIDR from CoreSight ID registers
  perf/smmuv3: Add devicetree support
  dt-bindings: Add Arm SMMUv3 PMCG binding
parents 8330904f df457ca9
Loading
Loading
Loading
Loading
+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>;
    };
+64 −2
Original line number Diff line number Diff line
@@ -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>
@@ -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
@@ -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
@@ -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;
@@ -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);
@@ -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 */
@@ -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,