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
This commit is contained in:
Коммит
1879a61f4a
|
@ -0,0 +1,70 @@
|
|||
# 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>;
|
||||
};
|
|
@ -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,7 +888,8 @@ static int smmu_pmu_probe(struct platform_device *pdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
smmu_pmu_get_acpi_options(smmu_pmu);
|
||||
if (!dev->of_node)
|
||||
smmu_pmu_get_acpi_options(smmu_pmu);
|
||||
|
||||
/* Pick one CPU to be the preferred one to use */
|
||||
smmu_pmu->on_cpu = raw_smp_processor_id();
|
||||
|
@ -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,
|
||||
|
|
Загрузка…
Ссылка в новой задаче