iommu/vt-d: Consolidate the struct dev_pasid_info add/remove
authorYi Liu <yi.l.liu@intel.com>
Fri, 8 Nov 2024 02:13:56 +0000 (10:13 +0800)
committerJoerg Roedel <jroedel@suse.de>
Fri, 8 Nov 2024 13:04:52 +0000 (14:04 +0100)
The domain_add_dev_pasid() and domain_remove_dev_pasid() are added to
consolidate the adding/removing of the struct dev_pasid_info. Besides,
it includes the cache tag assign/unassign as well.

This also prepares for adding domain replacement for pasid. The
set_dev_pasid callbacks need to deal with the dev_pasid_info for both old
and new domain. These two helpers make the life easier.

intel_iommu_set_dev_pasid() and intel_svm_set_dev_pasid() are updated to
use the helpers.

Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Yi Liu <yi.l.liu@intel.com>
Link: https://lore.kernel.org/r/20241107122234.7424-6-yi.l.liu@intel.com
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/intel/iommu.c
drivers/iommu/intel/iommu.h
drivers/iommu/intel/svm.c

index 2d1d208..103b109 100644 (file)
@@ -4036,8 +4036,8 @@ static int intel_iommu_iotlb_sync_map(struct iommu_domain *domain,
        return 0;
 }
 
-static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid,
-                                        struct iommu_domain *domain)
+void domain_remove_dev_pasid(struct iommu_domain *domain,
+                            struct device *dev, ioasid_t pasid)
 {
        struct device_domain_info *info = dev_iommu_priv_get(dev);
        struct dev_pasid_info *curr, *dev_pasid = NULL;
@@ -4045,10 +4045,12 @@ static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid,
        struct dmar_domain *dmar_domain;
        unsigned long flags;
 
-       if (domain->type == IOMMU_DOMAIN_IDENTITY) {
-               intel_pasid_tear_down_entry(iommu, dev, pasid, false);
+       if (!domain)
+               return;
+
+       /* Identity domain has no meta data for pasid. */
+       if (domain->type == IOMMU_DOMAIN_IDENTITY)
                return;
-       }
 
        dmar_domain = to_dmar_domain(domain);
        spin_lock_irqsave(&dmar_domain->lock, flags);
@@ -4066,7 +4068,52 @@ static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid,
        domain_detach_iommu(dmar_domain, iommu);
        intel_iommu_debugfs_remove_dev_pasid(dev_pasid);
        kfree(dev_pasid);
-       intel_pasid_tear_down_entry(iommu, dev, pasid, false);
+}
+
+static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid,
+                                        struct iommu_domain *domain)
+{
+       struct device_domain_info *info = dev_iommu_priv_get(dev);
+
+       intel_pasid_tear_down_entry(info->iommu, dev, pasid, false);
+       domain_remove_dev_pasid(domain, dev, pasid);
+}
+
+struct dev_pasid_info *
+domain_add_dev_pasid(struct iommu_domain *domain,
+                    struct device *dev, ioasid_t pasid)
+{
+       struct device_domain_info *info = dev_iommu_priv_get(dev);
+       struct dmar_domain *dmar_domain = to_dmar_domain(domain);
+       struct intel_iommu *iommu = info->iommu;
+       struct dev_pasid_info *dev_pasid;
+       unsigned long flags;
+       int ret;
+
+       dev_pasid = kzalloc(sizeof(*dev_pasid), GFP_KERNEL);
+       if (!dev_pasid)
+               return ERR_PTR(-ENOMEM);
+
+       ret = domain_attach_iommu(dmar_domain, iommu);
+       if (ret)
+               goto out_free;
+
+       ret = cache_tag_assign_domain(dmar_domain, dev, pasid);
+       if (ret)
+               goto out_detach_iommu;
+
+       dev_pasid->dev = dev;
+       dev_pasid->pasid = pasid;
+       spin_lock_irqsave(&dmar_domain->lock, flags);
+       list_add(&dev_pasid->link_domain, &dmar_domain->dev_pasids);
+       spin_unlock_irqrestore(&dmar_domain->lock, flags);
+
+       return dev_pasid;
+out_detach_iommu:
+       domain_detach_iommu(dmar_domain, iommu);
+out_free:
+       kfree(dev_pasid);
+       return ERR_PTR(ret);
 }
 
 static int intel_iommu_set_dev_pasid(struct iommu_domain *domain,
@@ -4077,7 +4124,6 @@ static int intel_iommu_set_dev_pasid(struct iommu_domain *domain,
        struct dmar_domain *dmar_domain = to_dmar_domain(domain);
        struct intel_iommu *iommu = info->iommu;
        struct dev_pasid_info *dev_pasid;
-       unsigned long flags;
        int ret;
 
        if (!pasid_supported(iommu) || dev_is_real_dma_subdevice(dev))
@@ -4093,17 +4139,9 @@ static int intel_iommu_set_dev_pasid(struct iommu_domain *domain,
        if (ret)
                return ret;
 
-       dev_pasid = kzalloc(sizeof(*dev_pasid), GFP_KERNEL);
-       if (!dev_pasid)
-               return -ENOMEM;
-
-       ret = domain_attach_iommu(dmar_domain, iommu);
-       if (ret)
-               goto out_free;
-
-       ret = cache_tag_assign_domain(dmar_domain, dev, pasid);
-       if (ret)
-               goto out_detach_iommu;
+       dev_pasid = domain_add_dev_pasid(domain, dev, pasid);
+       if (IS_ERR(dev_pasid))
+               return PTR_ERR(dev_pasid);
 
        if (dmar_domain->use_first_level)
                ret = domain_setup_first_level(iommu, dmar_domain,
@@ -4112,24 +4150,17 @@ static int intel_iommu_set_dev_pasid(struct iommu_domain *domain,
                ret = intel_pasid_setup_second_level(iommu, dmar_domain,
                                                     dev, pasid);
        if (ret)
-               goto out_unassign_tag;
+               goto out_remove_dev_pasid;
 
-       dev_pasid->dev = dev;
-       dev_pasid->pasid = pasid;
-       spin_lock_irqsave(&dmar_domain->lock, flags);
-       list_add(&dev_pasid->link_domain, &dmar_domain->dev_pasids);
-       spin_unlock_irqrestore(&dmar_domain->lock, flags);
+       domain_remove_dev_pasid(old, dev, pasid);
 
        if (domain->type & __IOMMU_DOMAIN_PAGING)
                intel_iommu_debugfs_create_dev_pasid(dev_pasid);
 
        return 0;
-out_unassign_tag:
-       cache_tag_unassign_domain(dmar_domain, dev, pasid);
-out_detach_iommu:
-       domain_detach_iommu(dmar_domain, iommu);
-out_free:
-       kfree(dev_pasid);
+
+out_remove_dev_pasid:
+       domain_remove_dev_pasid(domain, dev, pasid);
        return ret;
 }
 
index b391263..df0261e 100644 (file)
@@ -1228,6 +1228,12 @@ void domain_detach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu);
 void device_block_translation(struct device *dev);
 int paging_domain_compatible(struct iommu_domain *domain, struct device *dev);
 
+struct dev_pasid_info *
+domain_add_dev_pasid(struct iommu_domain *domain,
+                    struct device *dev, ioasid_t pasid);
+void domain_remove_dev_pasid(struct iommu_domain *domain,
+                            struct device *dev, ioasid_t pasid);
+
 int dmar_ir_support(void);
 
 void iommu_flush_write_buffer(struct intel_iommu *iommu);
index 4a2bd65..6c0685e 100644 (file)
@@ -115,43 +115,29 @@ static int intel_svm_set_dev_pasid(struct iommu_domain *domain,
                                   struct iommu_domain *old)
 {
        struct device_domain_info *info = dev_iommu_priv_get(dev);
-       struct dmar_domain *dmar_domain = to_dmar_domain(domain);
        struct intel_iommu *iommu = info->iommu;
        struct mm_struct *mm = domain->mm;
        struct dev_pasid_info *dev_pasid;
        unsigned long sflags;
-       unsigned long flags;
        int ret = 0;
 
-       dev_pasid = kzalloc(sizeof(*dev_pasid), GFP_KERNEL);
-       if (!dev_pasid)
-               return -ENOMEM;
-
-       dev_pasid->dev = dev;
-       dev_pasid->pasid = pasid;
-
-       ret = cache_tag_assign_domain(to_dmar_domain(domain), dev, pasid);
-       if (ret)
-               goto free_dev_pasid;
+       dev_pasid = domain_add_dev_pasid(domain, dev, pasid);
+       if (IS_ERR(dev_pasid))
+               return PTR_ERR(dev_pasid);
 
        /* Setup the pasid table: */
        sflags = cpu_feature_enabled(X86_FEATURE_LA57) ? PASID_FLAG_FL5LP : 0;
        ret = intel_pasid_setup_first_level(iommu, dev, mm->pgd, pasid,
                                            FLPT_DEFAULT_DID, sflags);
        if (ret)
-               goto unassign_tag;
+               goto out_remove_dev_pasid;
 
-       spin_lock_irqsave(&dmar_domain->lock, flags);
-       list_add(&dev_pasid->link_domain, &dmar_domain->dev_pasids);
-       spin_unlock_irqrestore(&dmar_domain->lock, flags);
+       domain_remove_dev_pasid(old, dev, pasid);
 
        return 0;
 
-unassign_tag:
-       cache_tag_unassign_domain(to_dmar_domain(domain), dev, pasid);
-free_dev_pasid:
-       kfree(dev_pasid);
-
+out_remove_dev_pasid:
+       domain_remove_dev_pasid(domain, dev, pasid);
        return ret;
 }