]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
iommu/vt-d: Support dirty tracking on PASID
authorZhenzhong Duan <zhenzhong.duan@intel.com>
Thu, 2 Apr 2026 06:57:26 +0000 (14:57 +0800)
committerJoerg Roedel <joerg.roedel@amd.com>
Thu, 2 Apr 2026 07:26:05 +0000 (09:26 +0200)
In order to support passthrough device with PASID capability in QEMU,
e.g., DSA device, kernel needs to support attaching PASID to a domain.

But attaching is not allowed if the domain is a second stage domain or
nested domain with dirty tracking.

The reason is kernel lacking support for dirty tracking on such domain
attached to PASID. By adding dirty tracking on PASID, the check can be
removed.

Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
Reviewed-by: Yi Liu <yi.l.liu@intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Link: https://lore.kernel.org/r/20260330101108.12594-4-zhenzhong.duan@intel.com
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
drivers/iommu/intel/iommu.c
drivers/iommu/intel/nested.c

index 965e0330ec4b03b8550d78af486cb541b21d3c8d..26135ff3a28907aed710da1a2e2bdceab8044586 100644 (file)
@@ -3618,9 +3618,6 @@ static int intel_iommu_set_dev_pasid(struct iommu_domain *domain,
        if (!pasid_supported(iommu) || dev_is_real_dma_subdevice(dev))
                return -EOPNOTSUPP;
 
-       if (domain->dirty_ops)
-               return -EINVAL;
-
        if (context_copied(iommu, info->bus, info->devfn))
                return -EBUSY;
 
@@ -3688,6 +3685,7 @@ static void *intel_iommu_hw_info(struct device *dev, u32 *length,
 static int domain_set_dirty_tracking(struct dmar_domain *domain, bool enable)
 {
        struct device_domain_info *info;
+       struct dev_pasid_info *dev_pasid;
        int ret = 0;
 
        lockdep_assert_held(&domain->lock);
@@ -3695,6 +3693,14 @@ static int domain_set_dirty_tracking(struct dmar_domain *domain, bool enable)
        list_for_each_entry(info, &domain->devices, link) {
                ret = intel_pasid_setup_dirty_tracking(info->iommu, info->dev,
                                                       IOMMU_NO_PASID, enable);
+               if (ret)
+                       return ret;
+       }
+
+       list_for_each_entry(dev_pasid, &domain->dev_pasids, link_domain) {
+               info = dev_iommu_priv_get(dev_pasid->dev);
+               ret = intel_pasid_setup_dirty_tracking(info->iommu, info->dev,
+                                                      dev_pasid->pasid, enable);
                if (ret)
                        break;
        }
index 16c82ba47d302bfc5d40298446a7bff6fc0c3327..2b979bec56cefeff1a2391cfac0db1725dcdd2cb 100644 (file)
@@ -148,7 +148,6 @@ static int intel_nested_set_dev_pasid(struct iommu_domain *domain,
 {
        struct device_domain_info *info = dev_iommu_priv_get(dev);
        struct dmar_domain *dmar_domain = to_dmar_domain(domain);
-       struct iommu_domain *s2_domain = &dmar_domain->s2_domain->domain;
        struct intel_iommu *iommu = info->iommu;
        struct dev_pasid_info *dev_pasid;
        int ret;
@@ -156,13 +155,10 @@ static int intel_nested_set_dev_pasid(struct iommu_domain *domain,
        if (!pasid_supported(iommu) || dev_is_real_dma_subdevice(dev))
                return -EOPNOTSUPP;
 
-       if (s2_domain->dirty_ops)
-               return -EINVAL;
-
        if (context_copied(iommu, info->bus, info->devfn))
                return -EBUSY;
 
-       ret = paging_domain_compatible(s2_domain, dev);
+       ret = paging_domain_compatible(&dmar_domain->s2_domain->domain, dev);
        if (ret)
                return ret;