iommu/arm-smmu-v3: Add struct arm_smmu_impl_ops
authorJason Gunthorpe <jgg@nvidia.com>
Thu, 29 Aug 2024 22:34:36 +0000 (15:34 -0700)
committerWill Deacon <will@kernel.org>
Fri, 30 Aug 2024 14:23:59 +0000 (15:23 +0100)
Mimicing the arm-smmu (v2) driver, introduce a struct arm_smmu_impl_ops to
accommodate impl routines.

Suggested-by: Will Deacon <will@kernel.org>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Link: https://lore.kernel.org/r/8fe9f3805568aabf771fc6706c116459016bf62d.1724970714.git.nicolinc@nvidia.com
Signed-off-by: Will Deacon <will@kernel.org>
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h

index f23245012681cb6bae6b6af93fa10de1ea99a92c..01dc752e9338b0590e594bb8b3e2691eced89431 100644 (file)
@@ -348,7 +348,12 @@ static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent)
 
 static struct arm_smmu_cmdq *arm_smmu_get_cmdq(struct arm_smmu_device *smmu)
 {
-       return &smmu->cmdq;
+       struct arm_smmu_cmdq *cmdq = NULL;
+
+       if (smmu->impl_ops && smmu->impl_ops->get_secondary_cmdq)
+               cmdq = smmu->impl_ops->get_secondary_cmdq(smmu);
+
+       return cmdq ?: &smmu->cmdq;
 }
 
 static bool arm_smmu_cmdq_needs_busy_polling(struct arm_smmu_device *smmu,
@@ -4052,6 +4057,14 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu)
                return ret;
        }
 
+       if (smmu->impl_ops && smmu->impl_ops->device_reset) {
+               ret = smmu->impl_ops->device_reset(smmu);
+               if (ret) {
+                       dev_err(smmu->dev, "failed to reset impl\n");
+                       return ret;
+               }
+       }
+
        return 0;
 }
 
@@ -4466,6 +4479,38 @@ static void arm_smmu_rmr_install_bypass_ste(struct arm_smmu_device *smmu)
        iort_put_rmr_sids(dev_fwnode(smmu->dev), &rmr_list);
 }
 
+static void arm_smmu_impl_remove(void *data)
+{
+       struct arm_smmu_device *smmu = data;
+
+       if (smmu->impl_ops && smmu->impl_ops->device_remove)
+               smmu->impl_ops->device_remove(smmu);
+}
+
+/*
+ * Probe all the compiled in implementations. Each one checks to see if it
+ * matches this HW and if so returns a devm_krealloc'd arm_smmu_device which
+ * replaces the callers. Otherwise the original is returned or ERR_PTR.
+ */
+static struct arm_smmu_device *arm_smmu_impl_probe(struct arm_smmu_device *smmu)
+{
+       struct arm_smmu_device *new_smmu = ERR_PTR(-ENODEV);
+       int ret;
+
+       /* Add impl probe */
+
+       if (new_smmu == ERR_PTR(-ENODEV))
+               return smmu;
+       if (IS_ERR(new_smmu))
+               return new_smmu;
+
+       ret = devm_add_action_or_reset(new_smmu->dev, arm_smmu_impl_remove,
+                                      new_smmu);
+       if (ret)
+               return ERR_PTR(ret);
+       return new_smmu;
+}
+
 static int arm_smmu_device_probe(struct platform_device *pdev)
 {
        int irq, ret;
@@ -4487,6 +4532,10 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       smmu = arm_smmu_impl_probe(smmu);
+       if (IS_ERR(smmu))
+               return PTR_ERR(smmu);
+
        /* Base address */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res)
index 21f034f0ff4c2107bf8315e54ec87a4bc3a31282..8d7a95b0dbd9725eef9b20f0e49bf31241391937 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/mmzone.h>
 #include <linux/sizes.h>
 
+struct arm_smmu_device;
+
 /* MMIO registers */
 #define ARM_SMMU_IDR0                  0x0
 #define IDR0_ST_LVL                    GENMASK(28, 27)
@@ -630,9 +632,17 @@ struct arm_smmu_strtab_cfg {
        u32                             strtab_base_cfg;
 };
 
+struct arm_smmu_impl_ops {
+       int (*device_reset)(struct arm_smmu_device *smmu);
+       void (*device_remove)(struct arm_smmu_device *smmu);
+       struct arm_smmu_cmdq *(*get_secondary_cmdq)(struct arm_smmu_device *smmu);
+};
+
 /* An SMMUv3 instance */
 struct arm_smmu_device {
        struct device                   *dev;
+       const struct arm_smmu_impl_ops  *impl_ops;
+
        void __iomem                    *base;
        void __iomem                    *page1;