]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
iommu/arm-smmu-v3: Add a global static IDENTITY domain
authorJason Gunthorpe <jgg@nvidia.com>
Mon, 26 Feb 2024 17:07:23 +0000 (13:07 -0400)
committerWill Deacon <will@kernel.org>
Thu, 29 Feb 2024 15:12:22 +0000 (15:12 +0000)
Move to the new static global for identity domains. Move all the logic out
of arm_smmu_attach_dev into an identity only function.

Reviewed-by: Michael Shavit <mshavit@google.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Tested-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
Tested-by: Nicolin Chen <nicolinc@nvidia.com>
Tested-by: Moritz Fischer <moritzf@google.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Link: https://lore.kernel.org/r/12-v6-96275f25c39d+2d4-smmuv3_newapi_p1_jgg@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 19a7f0468149cf296c9b3bd98121c426b38f83c9..842ff8a95baa1293dfbc24cdd446f94989ce1206 100644 (file)
@@ -2200,8 +2200,7 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
                return arm_smmu_sva_domain_alloc();
 
        if (type != IOMMU_DOMAIN_UNMANAGED &&
-           type != IOMMU_DOMAIN_DMA &&
-           type != IOMMU_DOMAIN_IDENTITY)
+           type != IOMMU_DOMAIN_DMA)
                return NULL;
 
        /*
@@ -2309,11 +2308,6 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain)
        struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
        struct arm_smmu_device *smmu = smmu_domain->smmu;
 
-       if (domain->type == IOMMU_DOMAIN_IDENTITY) {
-               smmu_domain->stage = ARM_SMMU_DOMAIN_BYPASS;
-               return 0;
-       }
-
        /* Restrict the stage to what we can actually support */
        if (!(smmu->features & ARM_SMMU_FEAT_TRANS_S1))
                smmu_domain->stage = ARM_SMMU_DOMAIN_S2;
@@ -2511,7 +2505,7 @@ static void arm_smmu_detach_dev(struct arm_smmu_master *master)
        struct arm_smmu_domain *smmu_domain;
        unsigned long flags;
 
-       if (!domain)
+       if (!domain || !(domain->type & __IOMMU_DOMAIN_PAGING))
                return;
 
        smmu_domain = to_smmu_domain(domain);
@@ -2574,15 +2568,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
 
        arm_smmu_detach_dev(master);
 
-       /*
-        * The SMMU does not support enabling ATS with bypass. When the STE is
-        * in bypass (STE.Config[2:0] == 0b100), ATS Translation Requests and
-        * Translated transactions are denied as though ATS is disabled for the
-        * stream (STE.EATS == 0b00), causing F_BAD_ATS_TREQ and
-        * F_TRANSL_FORBIDDEN events (IHI0070Ea 5.2 Stream Table Entry).
-        */
-       if (smmu_domain->stage != ARM_SMMU_DOMAIN_BYPASS)
-               master->ats_enabled = arm_smmu_ats_supported(master);
+       master->ats_enabled = arm_smmu_ats_supported(master);
 
        spin_lock_irqsave(&smmu_domain->devices_lock, flags);
        list_add(&master->domain_head, &smmu_domain->devices);
@@ -2619,13 +2605,6 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
                        arm_smmu_write_ctx_desc(master, IOMMU_NO_PASID,
                                                      NULL);
                break;
-       case ARM_SMMU_DOMAIN_BYPASS:
-               arm_smmu_make_bypass_ste(&target);
-               arm_smmu_install_ste_for_dev(master, &target);
-               if (master->cd_table.cdtab)
-                       arm_smmu_write_ctx_desc(master, IOMMU_NO_PASID,
-                                                     NULL);
-               break;
        }
 
        arm_smmu_enable_ats(master, smmu_domain);
@@ -2641,6 +2620,60 @@ out_unlock:
        return ret;
 }
 
+static int arm_smmu_attach_dev_ste(struct device *dev,
+                                  struct arm_smmu_ste *ste)
+{
+       struct arm_smmu_master *master = dev_iommu_priv_get(dev);
+
+       if (arm_smmu_master_sva_enabled(master))
+               return -EBUSY;
+
+       /*
+        * Do not allow any ASID to be changed while are working on the STE,
+        * otherwise we could miss invalidations.
+        */
+       mutex_lock(&arm_smmu_asid_lock);
+
+       /*
+        * The SMMU does not support enabling ATS with bypass/abort. When the
+        * STE is in bypass (STE.Config[2:0] == 0b100), ATS Translation Requests
+        * and Translated transactions are denied as though ATS is disabled for
+        * the stream (STE.EATS == 0b00), causing F_BAD_ATS_TREQ and
+        * F_TRANSL_FORBIDDEN events (IHI0070Ea 5.2 Stream Table Entry).
+        */
+       arm_smmu_detach_dev(master);
+
+       arm_smmu_install_ste_for_dev(master, ste);
+       mutex_unlock(&arm_smmu_asid_lock);
+
+       /*
+        * This has to be done after removing the master from the
+        * arm_smmu_domain->devices to avoid races updating the same context
+        * descriptor from arm_smmu_share_asid().
+        */
+       if (master->cd_table.cdtab)
+               arm_smmu_write_ctx_desc(master, IOMMU_NO_PASID, NULL);
+       return 0;
+}
+
+static int arm_smmu_attach_dev_identity(struct iommu_domain *domain,
+                                       struct device *dev)
+{
+       struct arm_smmu_ste ste;
+
+       arm_smmu_make_bypass_ste(&ste);
+       return arm_smmu_attach_dev_ste(dev, &ste);
+}
+
+static const struct iommu_domain_ops arm_smmu_identity_ops = {
+       .attach_dev = arm_smmu_attach_dev_identity,
+};
+
+static struct iommu_domain arm_smmu_identity_domain = {
+       .type = IOMMU_DOMAIN_IDENTITY,
+       .ops = &arm_smmu_identity_ops,
+};
+
 static int arm_smmu_map_pages(struct iommu_domain *domain, unsigned long iova,
                              phys_addr_t paddr, size_t pgsize, size_t pgcount,
                              int prot, gfp_t gfp, size_t *mapped)
@@ -3030,6 +3063,7 @@ static void arm_smmu_remove_dev_pasid(struct device *dev, ioasid_t pasid)
 }
 
 static struct iommu_ops arm_smmu_ops = {
+       .identity_domain        = &arm_smmu_identity_domain,
        .capable                = arm_smmu_capable,
        .domain_alloc           = arm_smmu_domain_alloc,
        .probe_device           = arm_smmu_probe_device,
index 6b63ea7dae72dac3f1a6d9eca585b87e1706eb76..23baf117e7e4b5ca0d45d9cb22f1459e894523f5 100644 (file)
@@ -712,7 +712,6 @@ struct arm_smmu_master {
 enum arm_smmu_domain_stage {
        ARM_SMMU_DOMAIN_S1 = 0,
        ARM_SMMU_DOMAIN_S2,
-       ARM_SMMU_DOMAIN_BYPASS,
 };
 
 struct arm_smmu_domain {