[PATCH 4/6] iommu/smmu: Create child devices for PMUs

Robin Murphy robin.murphy at arm.com
Thu Feb 17 06:24:18 PST 2022


Whilst SMMUv3 PMCGs are somewhat free-form, the SMMUv1/v2 PMU has a
well-defined and closely-coupled relationship with the main SMMU
interface. This makes it logical for the SMMU driver to be in charge of
consuming the firmware description and instantiating an abstract PMU
device directly, obviating the need for independent detection methods.

Signed-off-by: Robin Murphy <robin.murphy at arm.com>
---
 drivers/iommu/arm/arm-smmu/arm-smmu.c | 46 +++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c
index 8d6c8106fc1d..58daf81adae7 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
@@ -2070,6 +2070,45 @@ err_reset_platform_ops: __maybe_unused;
 	return err;
 }
 
+static int arm_smmu_pmu_init(struct arm_smmu_device *smmu,
+			     int irq_offset, int num_irqs)
+{
+	struct platform_device *pmu, *smmu_pdev;
+	int i, ret = -ENOMEM;
+
+	pmu = platform_device_alloc("arm-smmu-pmu", PLATFORM_DEVID_AUTO);
+	if (!pmu)
+		return -ENOMEM;
+
+	pmu->dev.parent = smmu->dev;
+	pmu->dev.platform_data = (__force void *)smmu->base + (3 << smmu->pgshift);
+	pmu->num_resources = num_irqs;
+	pmu->resource = kcalloc(num_irqs, sizeof(*pmu->resource), GFP_KERNEL);
+	if (!pmu->resource)
+		goto error;
+
+	smmu_pdev = to_platform_device(smmu->dev);
+	for (i = 0; i < num_irqs; i++) {
+		ret = platform_get_irq(smmu_pdev, irq_offset + i);
+		if (ret < 0)
+			goto error;
+
+		pmu->resource[i].start = ret;
+		pmu->resource[i].end = ret;
+		pmu->resource[i].flags = IORESOURCE_IRQ;
+	}
+
+	ret = platform_device_add(pmu);
+	if (ret)
+		goto error;
+
+	return 0;
+error:
+	pmu->dev.platform_data = NULL;
+	platform_device_put(pmu);
+	return ret;
+}
+
 static int arm_smmu_device_probe(struct platform_device *pdev)
 {
 	struct resource *res;
@@ -2216,6 +2255,13 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
 			goto err_unregister_device;
 	}
 
+	/* Try the PMU last so we don't have to worry about cleaning it up */
+	if (pmu_irqs) {
+		err = arm_smmu_pmu_init(smmu, global_irqs, pmu_irqs);
+		if (err)
+			dev_warn(dev, "Failed to create PMU device: %d", err);
+	}
+
 	return 0;
 
 err_unregister_device:
-- 
2.28.0.dirty




More information about the linux-arm-kernel mailing list