]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
iommu/arm-smmu-v3: Allow setting a S1 domain to a PASID
authorJason Gunthorpe <jgg@nvidia.com>
Tue, 25 Jun 2024 12:37:45 +0000 (09:37 -0300)
committerWill Deacon <will@kernel.org>
Tue, 2 Jul 2024 14:39:48 +0000 (15:39 +0100)
The SVA cleanup made the SSID logic entirely general so all we need to do
is call it with the correct cd table entry for a S1 domain.

This is slightly tricky because of the ASID and how the locking works, the
simple fix is to just update the ASID once we get the right locks.

Tested-by: Nicolin Chen <nicolinc@nvidia.com>
Tested-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Link: https://lore.kernel.org/r/14-v9-5cd718286059+79186-smmuv3_newapi_p2b_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 8e661442b5321f6c639128c8aa8b8a5b2bd579ec..8c3031fe542b2ee965ae402cbf3d1c3eea1df733 100644 (file)
@@ -2798,6 +2798,36 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
        return 0;
 }
 
+static int arm_smmu_s1_set_dev_pasid(struct iommu_domain *domain,
+                                     struct device *dev, ioasid_t id)
+{
+       struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+       struct arm_smmu_master *master = dev_iommu_priv_get(dev);
+       struct arm_smmu_device *smmu = master->smmu;
+       struct arm_smmu_cd target_cd;
+       int ret = 0;
+
+       mutex_lock(&smmu_domain->init_mutex);
+       if (!smmu_domain->smmu)
+               ret = arm_smmu_domain_finalise(smmu_domain, smmu);
+       else if (smmu_domain->smmu != smmu)
+               ret = -EINVAL;
+       mutex_unlock(&smmu_domain->init_mutex);
+       if (ret)
+               return ret;
+
+       if (smmu_domain->stage != ARM_SMMU_DOMAIN_S1)
+               return -EINVAL;
+
+       /*
+        * We can read cd.asid outside the lock because arm_smmu_set_pasid()
+        * will fix it
+        */
+       arm_smmu_make_s1_cd(&target_cd, master, smmu_domain);
+       return arm_smmu_set_pasid(master, to_smmu_domain(domain), id,
+                                 &target_cd);
+}
+
 static void arm_smmu_update_ste(struct arm_smmu_master *master,
                                struct iommu_domain *sid_domain,
                                bool ats_enabled)
@@ -2825,7 +2855,7 @@ static void arm_smmu_update_ste(struct arm_smmu_master *master,
 
 int arm_smmu_set_pasid(struct arm_smmu_master *master,
                       struct arm_smmu_domain *smmu_domain, ioasid_t pasid,
-                      const struct arm_smmu_cd *cd)
+                      struct arm_smmu_cd *cd)
 {
        struct iommu_domain *sid_domain = iommu_get_domain_for_dev(master->dev);
        struct arm_smmu_attach_state state = {
@@ -2858,6 +2888,14 @@ int arm_smmu_set_pasid(struct arm_smmu_master *master,
        if (ret)
                goto out_unlock;
 
+       /*
+        * We don't want to obtain to the asid_lock too early, so fix up the
+        * caller set ASID under the lock in case it changed.
+        */
+       cd->data[0] &= ~cpu_to_le64(CTXDESC_CD_0_ASID);
+       cd->data[0] |= cpu_to_le64(
+               FIELD_PREP(CTXDESC_CD_0_ASID, smmu_domain->cd.asid));
+
        arm_smmu_write_cd_entry(master, pasid, cdptr, cd);
        arm_smmu_update_ste(master, sid_domain, state.ats_enabled);
 
@@ -3376,6 +3414,7 @@ static struct iommu_ops arm_smmu_ops = {
        .owner                  = THIS_MODULE,
        .default_domain_ops = &(const struct iommu_domain_ops) {
                .attach_dev             = arm_smmu_attach_dev,
+               .set_dev_pasid          = arm_smmu_s1_set_dev_pasid,
                .map_pages              = arm_smmu_map_pages,
                .unmap_pages            = arm_smmu_unmap_pages,
                .flush_iotlb_all        = arm_smmu_flush_iotlb_all,
index cdd426efb384d265b2850e5eafd4425adf416c01..91ec2d49ecbf2e4c14d2ad9fe4d6b9727c6e94e1 100644 (file)
@@ -801,7 +801,7 @@ void arm_smmu_write_cd_entry(struct arm_smmu_master *master, int ssid,
 
 int arm_smmu_set_pasid(struct arm_smmu_master *master,
                       struct arm_smmu_domain *smmu_domain, ioasid_t pasid,
-                      const struct arm_smmu_cd *cd);
+                      struct arm_smmu_cd *cd);
 
 void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid);
 void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,