iommu/vt-d: Fix issue in computing domain's iommu_snooping flag
authorJiang Liu <jiang.liu@linux.intel.com>
Fri, 11 Jul 2014 06:19:37 +0000 (14:19 +0800)
committerJoerg Roedel <jroedel@suse.de>
Wed, 23 Jul 2014 14:04:47 +0000 (16:04 +0200)
IOMMU units may dynamically attached to/detached from domains,
so we should scan all active IOMMU units when computing iommu_snooping
flag for a domain instead of only scanning IOMMU units associated
with the domain.

Also check snooping and superpage capabilities when hot-adding DMAR units.

Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/intel-iommu.c

index cd1ba24c766ad74368707e9ace7f0afd968a6ca3..58cc2b75d7aeb4268b7822b9703e5086c6376389 100644 (file)
@@ -633,50 +633,56 @@ static void domain_update_iommu_coherency(struct dmar_domain *domain)
        rcu_read_unlock();
 }
 
-static void domain_update_iommu_snooping(struct dmar_domain *domain)
+static int domain_update_iommu_snooping(struct intel_iommu *skip)
 {
-       int i;
-
-       domain->iommu_snooping = 1;
+       struct dmar_drhd_unit *drhd;
+       struct intel_iommu *iommu;
+       int ret = 1;
 
-       for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) {
-               if (!ecap_sc_support(g_iommus[i]->ecap)) {
-                       domain->iommu_snooping = 0;
-                       break;
+       rcu_read_lock();
+       for_each_active_iommu(iommu, drhd) {
+               if (iommu != skip) {
+                       if (!ecap_sc_support(iommu->ecap)) {
+                               ret = 0;
+                               break;
+                       }
                }
        }
+       rcu_read_unlock();
+
+       return ret;
 }
 
-static void domain_update_iommu_superpage(struct dmar_domain *domain)
+static int domain_update_iommu_superpage(struct intel_iommu *skip)
 {
        struct dmar_drhd_unit *drhd;
-       struct intel_iommu *iommu = NULL;
+       struct intel_iommu *iommu;
        int mask = 0xf;
 
        if (!intel_iommu_superpage) {
-               domain->iommu_superpage = 0;
-               return;
+               return 0;
        }
 
        /* set iommu_superpage to the smallest common denominator */
        rcu_read_lock();
        for_each_active_iommu(iommu, drhd) {
-               mask &= cap_super_page_val(iommu->cap);
-               if (!mask) {
-                       break;
+               if (iommu != skip) {
+                       mask &= cap_super_page_val(iommu->cap);
+                       if (!mask)
+                               break;
                }
        }
        rcu_read_unlock();
 
-       domain->iommu_superpage = fls(mask);
+       return fls(mask);
 }
 
 /* Some capabilities may be different across iommus */
 static void domain_update_iommu_cap(struct dmar_domain *domain)
 {
        domain_update_iommu_coherency(domain);
-       domain_update_iommu_snooping(domain);
-       domain_update_iommu_superpage(domain);
+       domain->iommu_snooping = domain_update_iommu_snooping(NULL);
+       domain->iommu_superpage = domain_update_iommu_superpage(NULL);
 }
 
 static struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn)