iommu/vt-d: Fix missed device TLB cache tag
authorLu Baolu <baolu.lu@linux.intel.com>
Thu, 20 Jun 2024 06:29:40 +0000 (14:29 +0800)
committerJoerg Roedel <jroedel@suse.de>
Thu, 27 Jun 2024 10:14:19 +0000 (12:14 +0200)
When a domain is attached to a device, the required cache tags are
assigned to the domain so that the related caches can be flushed
whenever it is needed. The device TLB cache tag is created based
on whether the ats_enabled field of the device's iommu data is set.
This creates an ordered dependency between cache tag assignment and
ATS enabling.

The device TLB cache tag would not be created if device's ATS is
enabled after the cache tag assignment. This causes devices with PCI
ATS support to malfunction.

The ATS control is exclusively owned by the iommu driver. Hence, move
cache_tag_assign_domain() after PCI ATS enabling to make sure that the
device TLB cache tag is created for the domain.

Fixes: 3b1d9e2b2d68 ("iommu/vt-d: Add cache tag assignment interface")
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Link: https://lore.kernel.org/r/20240620062940.201786-1-baolu.lu@linux.intel.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/intel/iommu.c

index 2e9811bf2a4e5573aa364ba11ed05f3dda474ce9..fd11a080380c844278c4c34e08582e42848e23b2 100644 (file)
@@ -2114,12 +2114,6 @@ static int dmar_domain_attach_device(struct dmar_domain *domain,
        if (ret)
                return ret;
 
-       ret = cache_tag_assign_domain(domain, dev, IOMMU_NO_PASID);
-       if (ret) {
-               domain_detach_iommu(domain, iommu);
-               return ret;
-       }
-
        info->domain = domain;
        spin_lock_irqsave(&domain->lock, flags);
        list_add(&info->link, &domain->devices);
@@ -2137,15 +2131,21 @@ static int dmar_domain_attach_device(struct dmar_domain *domain,
        else
                ret = intel_pasid_setup_second_level(iommu, domain, dev, IOMMU_NO_PASID);
 
-       if (ret) {
-               device_block_translation(dev);
-               return ret;
-       }
+       if (ret)
+               goto out_block_translation;
 
        if (sm_supported(info->iommu) || !domain_type_is_si(info->domain))
                iommu_enable_pci_caps(info);
 
+       ret = cache_tag_assign_domain(domain, dev, IOMMU_NO_PASID);
+       if (ret)
+               goto out_block_translation;
+
        return 0;
+
+out_block_translation:
+       device_block_translation(dev);
+       return ret;
 }
 
 /**