]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/iommu/intel-iommu.c
Merge tag 'pm+acpi-3.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[mirror_ubuntu-artful-kernel.git] / drivers / iommu / intel-iommu.c
index 51b6b77dc3e58ce7b86d123948dff9de808106f9..d1f5caad04f99a8ed2e3781d5bcedce7c324564e 100644 (file)
@@ -45,7 +45,6 @@
 #include <asm/iommu.h>
 
 #include "irq_remapping.h"
-#include "pci.h"
 
 #define ROOT_SIZE              VTD_PAGE_SIZE
 #define CONTEXT_SIZE           VTD_PAGE_SIZE
@@ -304,7 +303,7 @@ static inline bool dma_pte_present(struct dma_pte *pte)
 
 static inline bool dma_pte_superpage(struct dma_pte *pte)
 {
-       return (pte->val & (1 << 7));
+       return (pte->val & DMA_PTE_LARGE_PAGE);
 }
 
 static inline int first_pte_in_page(struct dma_pte *pte)
@@ -321,16 +320,13 @@ static inline int first_pte_in_page(struct dma_pte *pte)
 static struct dmar_domain *si_domain;
 static int hw_pass_through = 1;
 
-/* devices under the same p2p bridge are owned in one domain */
-#define DOMAIN_FLAG_P2P_MULTIPLE_DEVICES (1 << 0)
-
 /* domain represents a virtual machine, more than one devices
  * across iommus may be owned in one domain, e.g. kvm guest.
  */
-#define DOMAIN_FLAG_VIRTUAL_MACHINE    (1 << 1)
+#define DOMAIN_FLAG_VIRTUAL_MACHINE    (1 << 0)
 
 /* si_domain contains mulitple devices */
-#define DOMAIN_FLAG_STATIC_IDENTITY    (1 << 2)
+#define DOMAIN_FLAG_STATIC_IDENTITY    (1 << 1)
 
 /* define the limit of IOMMUs supported in each domain */
 #ifdef CONFIG_X86
@@ -429,6 +425,8 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain,
                                       struct device *dev);
 static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
                                           struct device *dev);
+static int domain_detach_iommu(struct dmar_domain *domain,
+                              struct intel_iommu *iommu);
 
 #ifdef CONFIG_INTEL_IOMMU_DEFAULT_ON
 int dmar_disabled = 0;
@@ -451,7 +449,7 @@ EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped);
 static DEFINE_SPINLOCK(device_domain_lock);
 static LIST_HEAD(device_domain_list);
 
-static struct iommu_ops intel_iommu_ops;
+static const struct iommu_ops intel_iommu_ops;
 
 static int __init intel_iommu_setup(char *str)
 {
@@ -540,6 +538,24 @@ void free_iova_mem(struct iova *iova)
        kmem_cache_free(iommu_iova_cache, iova);
 }
 
+static inline int domain_type_is_vm(struct dmar_domain *domain)
+{
+       return domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE;
+}
+
+static inline int domain_type_is_vm_or_si(struct dmar_domain *domain)
+{
+       return domain->flags & (DOMAIN_FLAG_VIRTUAL_MACHINE |
+                               DOMAIN_FLAG_STATIC_IDENTITY);
+}
+
+static inline int domain_pfn_supported(struct dmar_domain *domain,
+                                      unsigned long pfn)
+{
+       int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
+
+       return !(addr_width < BITS_PER_LONG && pfn >> addr_width);
+}
 
 static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw)
 {
@@ -580,9 +596,7 @@ static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
        int iommu_id;
 
        /* si_domain and vm domain should not get here. */
-       BUG_ON(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE);
-       BUG_ON(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY);
-
+       BUG_ON(domain_type_is_vm_or_si(domain));
        iommu_id = find_first_bit(domain->iommu_bmp, g_num_of_iommus);
        if (iommu_id < 0 || iommu_id >= g_num_of_iommus)
                return NULL;
@@ -619,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)
@@ -671,7 +691,7 @@ static struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devf
        struct intel_iommu *iommu;
        struct device *tmp;
        struct pci_dev *ptmp, *pdev = NULL;
-       u16 segment;
+       u16 segment = 0;
        int i;
 
        if (dev_is_pci(dev)) {
@@ -816,14 +836,13 @@ out:
 static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
                                      unsigned long pfn, int *target_level)
 {
-       int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
        struct dma_pte *parent, *pte = NULL;
        int level = agaw_to_level(domain->agaw);
        int offset;
 
        BUG_ON(!domain->pgd);
 
-       if (addr_width < BITS_PER_LONG && pfn >> addr_width)
+       if (!domain_pfn_supported(domain, pfn))
                /* Address beyond IOMMU's addressing capabilities. */
                return NULL;
 
@@ -849,13 +868,11 @@ static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
 
                        domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
                        pteval = ((uint64_t)virt_to_dma_pfn(tmp_page) << VTD_PAGE_SHIFT) | DMA_PTE_READ | DMA_PTE_WRITE;
-                       if (cmpxchg64(&pte->val, 0ULL, pteval)) {
+                       if (cmpxchg64(&pte->val, 0ULL, pteval))
                                /* Someone else set it while we were thinking; use theirs. */
                                free_pgtable_page(tmp_page);
-                       } else {
-                               dma_pte_addr(pte);
+                       else
                                domain_flush_cache(domain, pte, sizeof(*pte));
-                       }
                }
                if (level == 1)
                        break;
@@ -892,7 +909,7 @@ static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
                        break;
                }
 
-               if (pte->val & DMA_PTE_LARGE_PAGE) {
+               if (dma_pte_superpage(pte)) {
                        *large_page = total;
                        return pte;
                }
@@ -908,12 +925,11 @@ static void dma_pte_clear_range(struct dmar_domain *domain,
                                unsigned long start_pfn,
                                unsigned long last_pfn)
 {
-       int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
        unsigned int large_page = 1;
        struct dma_pte *first_pte, *pte;
 
-       BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
-       BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
+       BUG_ON(!domain_pfn_supported(domain, start_pfn));
+       BUG_ON(!domain_pfn_supported(domain, last_pfn));
        BUG_ON(start_pfn > last_pfn);
 
        /* we don't need lock here; nobody else touches the iova range */
@@ -974,12 +990,12 @@ static void dma_pte_free_pagetable(struct dmar_domain *domain,
                                   unsigned long start_pfn,
                                   unsigned long last_pfn)
 {
-       int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
-
-       BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
-       BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
+       BUG_ON(!domain_pfn_supported(domain, start_pfn));
+       BUG_ON(!domain_pfn_supported(domain, last_pfn));
        BUG_ON(start_pfn > last_pfn);
 
+       dma_pte_clear_range(domain, start_pfn, last_pfn);
+
        /* We don't need lock here; nobody else touches the iova range */
        dma_pte_free_level(domain, agaw_to_level(domain->agaw),
                           domain->pgd, 0, start_pfn, last_pfn);
@@ -1077,11 +1093,10 @@ struct page *domain_unmap(struct dmar_domain *domain,
                          unsigned long start_pfn,
                          unsigned long last_pfn)
 {
-       int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
        struct page *freelist = NULL;
 
-       BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
-       BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
+       BUG_ON(!domain_pfn_supported(domain, start_pfn));
+       BUG_ON(!domain_pfn_supported(domain, last_pfn));
        BUG_ON(start_pfn > last_pfn);
 
        /* we don't need lock here; nobody else touches the iova range */
@@ -1275,7 +1290,8 @@ iommu_support_dev_iotlb (struct dmar_domain *domain, struct intel_iommu *iommu,
 
        spin_lock_irqsave(&device_domain_lock, flags);
        list_for_each_entry(info, &domain->devices, link)
-               if (info->bus == bus && info->devfn == devfn) {
+               if (info->iommu == iommu && info->bus == bus &&
+                   info->devfn == devfn) {
                        found = 1;
                        break;
                }
@@ -1384,7 +1400,7 @@ static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu)
        raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
 }
 
-static int iommu_enable_translation(struct intel_iommu *iommu)
+static void iommu_enable_translation(struct intel_iommu *iommu)
 {
        u32 sts;
        unsigned long flags;
@@ -1398,10 +1414,9 @@ static int iommu_enable_translation(struct intel_iommu *iommu)
                      readl, (sts & DMA_GSTS_TES), sts);
 
        raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
-       return 0;
 }
 
-static int iommu_disable_translation(struct intel_iommu *iommu)
+static void iommu_disable_translation(struct intel_iommu *iommu)
 {
        u32 sts;
        unsigned long flag;
@@ -1415,7 +1430,6 @@ static int iommu_disable_translation(struct intel_iommu *iommu)
                      readl, (!(sts & DMA_GSTS_TES)), sts);
 
        raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
-       return 0;
 }
 
 
@@ -1462,8 +1476,7 @@ static int iommu_init_domains(struct intel_iommu *iommu)
 static void free_dmar_iommu(struct intel_iommu *iommu)
 {
        struct dmar_domain *domain;
-       int i, count;
-       unsigned long flags;
+       int i;
 
        if ((iommu->domains) && (iommu->domain_ids)) {
                for_each_set_bit(i, iommu->domain_ids, cap_ndoms(iommu->cap)) {
@@ -1476,11 +1489,8 @@ static void free_dmar_iommu(struct intel_iommu *iommu)
 
                        domain = iommu->domains[i];
                        clear_bit(i, iommu->domain_ids);
-
-                       spin_lock_irqsave(&domain->iommu_lock, flags);
-                       count = --domain->iommu_count;
-                       spin_unlock_irqrestore(&domain->iommu_lock, flags);
-                       if (count == 0)
+                       if (domain_detach_iommu(domain, iommu) == 0 &&
+                           !domain_type_is_vm(domain))
                                domain_exit(domain);
                }
        }
@@ -1499,7 +1509,7 @@ static void free_dmar_iommu(struct intel_iommu *iommu)
        free_context_table(iommu);
 }
 
-static struct dmar_domain *alloc_domain(bool vm)
+static struct dmar_domain *alloc_domain(int flags)
 {
        /* domain id for virtual machine, it won't be set in context */
        static atomic_t vm_domid = ATOMIC_INIT(0);
@@ -1509,46 +1519,62 @@ static struct dmar_domain *alloc_domain(bool vm)
        if (!domain)
                return NULL;
 
+       memset(domain, 0, sizeof(*domain));
        domain->nid = -1;
-       domain->iommu_count = 0;
-       memset(domain->iommu_bmp, 0, sizeof(domain->iommu_bmp));
-       domain->flags = 0;
+       domain->flags = flags;
        spin_lock_init(&domain->iommu_lock);
        INIT_LIST_HEAD(&domain->devices);
-       if (vm) {
+       if (flags & DOMAIN_FLAG_VIRTUAL_MACHINE)
                domain->id = atomic_inc_return(&vm_domid);
-               domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE;
-       }
 
        return domain;
 }
 
-static int iommu_attach_domain(struct dmar_domain *domain,
-                              struct intel_iommu *iommu)
+static int __iommu_attach_domain(struct dmar_domain *domain,
+                                struct intel_iommu *iommu)
 {
        int num;
        unsigned long ndomains;
-       unsigned long flags;
 
        ndomains = cap_ndoms(iommu->cap);
-
-       spin_lock_irqsave(&iommu->lock, flags);
-
        num = find_first_zero_bit(iommu->domain_ids, ndomains);
-       if (num >= ndomains) {
-               spin_unlock_irqrestore(&iommu->lock, flags);
-               printk(KERN_ERR "IOMMU: no free domain ids\n");
-               return -ENOMEM;
+       if (num < ndomains) {
+               set_bit(num, iommu->domain_ids);
+               iommu->domains[num] = domain;
+       } else {
+               num = -ENOSPC;
        }
 
-       domain->id = num;
-       domain->iommu_count++;
-       set_bit(num, iommu->domain_ids);
-       set_bit(iommu->seq_id, domain->iommu_bmp);
-       iommu->domains[num] = domain;
+       return num;
+}
+
+static int iommu_attach_domain(struct dmar_domain *domain,
+                              struct intel_iommu *iommu)
+{
+       int num;
+       unsigned long flags;
+
+       spin_lock_irqsave(&iommu->lock, flags);
+       num = __iommu_attach_domain(domain, iommu);
        spin_unlock_irqrestore(&iommu->lock, flags);
+       if (num < 0)
+               pr_err("IOMMU: no free domain ids\n");
 
-       return 0;
+       return num;
+}
+
+static int iommu_attach_vm_domain(struct dmar_domain *domain,
+                                 struct intel_iommu *iommu)
+{
+       int num;
+       unsigned long ndomains;
+
+       ndomains = cap_ndoms(iommu->cap);
+       for_each_set_bit(num, iommu->domain_ids, ndomains)
+               if (iommu->domains[num] == domain)
+                       return num;
+
+       return __iommu_attach_domain(domain, iommu);
 }
 
 static void iommu_detach_domain(struct dmar_domain *domain,
@@ -1558,17 +1584,53 @@ static void iommu_detach_domain(struct dmar_domain *domain,
        int num, ndomains;
 
        spin_lock_irqsave(&iommu->lock, flags);
-       ndomains = cap_ndoms(iommu->cap);
-       for_each_set_bit(num, iommu->domain_ids, ndomains) {
-               if (iommu->domains[num] == domain) {
-                       clear_bit(num, iommu->domain_ids);
-                       iommu->domains[num] = NULL;
-                       break;
+       if (domain_type_is_vm_or_si(domain)) {
+               ndomains = cap_ndoms(iommu->cap);
+               for_each_set_bit(num, iommu->domain_ids, ndomains) {
+                       if (iommu->domains[num] == domain) {
+                               clear_bit(num, iommu->domain_ids);
+                               iommu->domains[num] = NULL;
+                               break;
+                       }
                }
+       } else {
+               clear_bit(domain->id, iommu->domain_ids);
+               iommu->domains[domain->id] = NULL;
        }
        spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
+static void domain_attach_iommu(struct dmar_domain *domain,
+                              struct intel_iommu *iommu)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&domain->iommu_lock, flags);
+       if (!test_and_set_bit(iommu->seq_id, domain->iommu_bmp)) {
+               domain->iommu_count++;
+               if (domain->iommu_count == 1)
+                       domain->nid = iommu->node;
+               domain_update_iommu_cap(domain);
+       }
+       spin_unlock_irqrestore(&domain->iommu_lock, flags);
+}
+
+static int domain_detach_iommu(struct dmar_domain *domain,
+                              struct intel_iommu *iommu)
+{
+       unsigned long flags;
+       int count = INT_MAX;
+
+       spin_lock_irqsave(&domain->iommu_lock, flags);
+       if (test_and_clear_bit(iommu->seq_id, domain->iommu_bmp)) {
+               count = --domain->iommu_count;
+               domain_update_iommu_cap(domain);
+       }
+       spin_unlock_irqrestore(&domain->iommu_lock, flags);
+
+       return count;
+}
+
 static struct iova_domain reserved_iova_list;
 static struct lock_class_key reserved_rbtree_key;
 
@@ -1706,9 +1768,7 @@ static void domain_exit(struct dmar_domain *domain)
        /* clear attached or cached domains */
        rcu_read_lock();
        for_each_active_iommu(iommu, drhd)
-               if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
-                   test_bit(iommu->seq_id, domain->iommu_bmp))
-                       iommu_detach_domain(domain, iommu);
+               iommu_detach_domain(domain, iommu);
        rcu_read_unlock();
 
        dma_free_pagelist(freelist);
@@ -1723,8 +1783,6 @@ static int domain_context_mapping_one(struct dmar_domain *domain,
        struct context_entry *context;
        unsigned long flags;
        struct dma_pte *pgd;
-       unsigned long num;
-       unsigned long ndomains;
        int id;
        int agaw;
        struct device_domain_info *info = NULL;
@@ -1748,31 +1806,14 @@ static int domain_context_mapping_one(struct dmar_domain *domain,
        id = domain->id;
        pgd = domain->pgd;
 
-       if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
-           domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) {
-               int found = 0;
-
-               /* find an available domain id for this device in iommu */
-               ndomains = cap_ndoms(iommu->cap);
-               for_each_set_bit(num, iommu->domain_ids, ndomains) {
-                       if (iommu->domains[num] == domain) {
-                               id = num;
-                               found = 1;
-                               break;
-                       }
-               }
-
-               if (found == 0) {
-                       num = find_first_zero_bit(iommu->domain_ids, ndomains);
-                       if (num >= ndomains) {
+       if (domain_type_is_vm_or_si(domain)) {
+               if (domain_type_is_vm(domain)) {
+                       id = iommu_attach_vm_domain(domain, iommu);
+                       if (id < 0) {
                                spin_unlock_irqrestore(&iommu->lock, flags);
-                               printk(KERN_ERR "IOMMU: no free domain ids\n");
+                               pr_err("IOMMU: no free domain ids\n");
                                return -EFAULT;
                        }
-
-                       set_bit(num, iommu->domain_ids);
-                       iommu->domains[num] = domain;
-                       id = num;
                }
 
                /* Skip top levels of page tables for
@@ -1824,72 +1865,68 @@ static int domain_context_mapping_one(struct dmar_domain *domain,
                                           (((u16)bus) << 8) | devfn,
                                           DMA_CCMD_MASK_NOBIT,
                                           DMA_CCMD_DEVICE_INVL);
-               iommu->flush.flush_iotlb(iommu, domain->id, 0, 0, DMA_TLB_DSI_FLUSH);
+               iommu->flush.flush_iotlb(iommu, id, 0, 0, DMA_TLB_DSI_FLUSH);
        } else {
                iommu_flush_write_buffer(iommu);
        }
        iommu_enable_dev_iotlb(info);
        spin_unlock_irqrestore(&iommu->lock, flags);
 
-       spin_lock_irqsave(&domain->iommu_lock, flags);
-       if (!test_and_set_bit(iommu->seq_id, domain->iommu_bmp)) {
-               domain->iommu_count++;
-               if (domain->iommu_count == 1)
-                       domain->nid = iommu->node;
-               domain_update_iommu_cap(domain);
-       }
-       spin_unlock_irqrestore(&domain->iommu_lock, flags);
+       domain_attach_iommu(domain, iommu);
+
        return 0;
 }
 
+struct domain_context_mapping_data {
+       struct dmar_domain *domain;
+       struct intel_iommu *iommu;
+       int translation;
+};
+
+static int domain_context_mapping_cb(struct pci_dev *pdev,
+                                    u16 alias, void *opaque)
+{
+       struct domain_context_mapping_data *data = opaque;
+
+       return domain_context_mapping_one(data->domain, data->iommu,
+                                         PCI_BUS_NUM(alias), alias & 0xff,
+                                         data->translation);
+}
+
 static int
 domain_context_mapping(struct dmar_domain *domain, struct device *dev,
                       int translation)
 {
-       int ret;
-       struct pci_dev *pdev, *tmp, *parent;
        struct intel_iommu *iommu;
        u8 bus, devfn;
+       struct domain_context_mapping_data data;
 
        iommu = device_to_iommu(dev, &bus, &devfn);
        if (!iommu)
                return -ENODEV;
 
-       ret = domain_context_mapping_one(domain, iommu, bus, devfn,
-                                        translation);
-       if (ret || !dev_is_pci(dev))
-               return ret;
-
-       /* dependent device mapping */
-       pdev = to_pci_dev(dev);
-       tmp = pci_find_upstream_pcie_bridge(pdev);
-       if (!tmp)
-               return 0;
-       /* Secondary interface's bus number and devfn 0 */
-       parent = pdev->bus->self;
-       while (parent != tmp) {
-               ret = domain_context_mapping_one(domain, iommu,
-                                                parent->bus->number,
-                                                parent->devfn, translation);
-               if (ret)
-                       return ret;
-               parent = parent->bus->self;
-       }
-       if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
-               return domain_context_mapping_one(domain, iommu,
-                                       tmp->subordinate->number, 0,
-                                       translation);
-       else /* this is a legacy PCI bridge */
-               return domain_context_mapping_one(domain, iommu,
-                                                 tmp->bus->number,
-                                                 tmp->devfn,
+       if (!dev_is_pci(dev))
+               return domain_context_mapping_one(domain, iommu, bus, devfn,
                                                  translation);
+
+       data.domain = domain;
+       data.iommu = iommu;
+       data.translation = translation;
+
+       return pci_for_each_dma_alias(to_pci_dev(dev),
+                                     &domain_context_mapping_cb, &data);
+}
+
+static int domain_context_mapped_cb(struct pci_dev *pdev,
+                                   u16 alias, void *opaque)
+{
+       struct intel_iommu *iommu = opaque;
+
+       return !device_context_mapped(iommu, PCI_BUS_NUM(alias), alias & 0xff);
 }
 
 static int domain_context_mapped(struct device *dev)
 {
-       int ret;
-       struct pci_dev *pdev, *tmp, *parent;
        struct intel_iommu *iommu;
        u8 bus, devfn;
 
@@ -1897,30 +1934,11 @@ static int domain_context_mapped(struct device *dev)
        if (!iommu)
                return -ENODEV;
 
-       ret = device_context_mapped(iommu, bus, devfn);
-       if (!ret || !dev_is_pci(dev))
-               return ret;
+       if (!dev_is_pci(dev))
+               return device_context_mapped(iommu, bus, devfn);
 
-       /* dependent device mapping */
-       pdev = to_pci_dev(dev);
-       tmp = pci_find_upstream_pcie_bridge(pdev);
-       if (!tmp)
-               return ret;
-       /* Secondary interface's bus number and devfn 0 */
-       parent = pdev->bus->self;
-       while (parent != tmp) {
-               ret = device_context_mapped(iommu, parent->bus->number,
-                                           parent->devfn);
-               if (!ret)
-                       return ret;
-               parent = parent->bus->self;
-       }
-       if (pci_is_pcie(tmp))
-               return device_context_mapped(iommu, tmp->subordinate->number,
-                                            0);
-       else
-               return device_context_mapped(iommu, tmp->bus->number,
-                                            tmp->devfn);
+       return !pci_for_each_dma_alias(to_pci_dev(dev),
+                                      domain_context_mapped_cb, iommu);
 }
 
 /* Returns a number of VTD pages, but aligned to MM page size */
@@ -1965,12 +1983,11 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
 {
        struct dma_pte *first_pte = NULL, *pte = NULL;
        phys_addr_t uninitialized_var(pteval);
-       int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
        unsigned long sg_res;
        unsigned int largepage_lvl = 0;
        unsigned long lvl_pages = 0;
 
-       BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> addr_width);
+       BUG_ON(!domain_pfn_supported(domain, iov_pfn + nr_pages - 1));
 
        if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
                return -EINVAL;
@@ -2004,12 +2021,14 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
                        /* It is large page*/
                        if (largepage_lvl > 1) {
                                pteval |= DMA_PTE_LARGE_PAGE;
-                               /* Ensure that old small page tables are removed to make room
-                                  for superpage, if they exist. */
-                               dma_pte_clear_range(domain, iov_pfn,
-                                                   iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
+                               lvl_pages = lvl_to_nr_pages(largepage_lvl);
+                               /*
+                                * Ensure that old small page tables are
+                                * removed to make room for superpage,
+                                * if they exist.
+                                */
                                dma_pte_free_pagetable(domain, iov_pfn,
-                                                      iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
+                                                      iov_pfn + lvl_pages - 1);
                        } else {
                                pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE;
                        }
@@ -2102,31 +2121,20 @@ static inline void unlink_domain_info(struct device_domain_info *info)
 
 static void domain_remove_dev_info(struct dmar_domain *domain)
 {
-       struct device_domain_info *info;
-       unsigned long flags, flags2;
+       struct device_domain_info *info, *tmp;
+       unsigned long flags;
 
        spin_lock_irqsave(&device_domain_lock, flags);
-       while (!list_empty(&domain->devices)) {
-               info = list_entry(domain->devices.next,
-                       struct device_domain_info, link);
+       list_for_each_entry_safe(info, tmp, &domain->devices, link) {
                unlink_domain_info(info);
                spin_unlock_irqrestore(&device_domain_lock, flags);
 
                iommu_disable_dev_iotlb(info);
                iommu_detach_dev(info->iommu, info->bus, info->devfn);
 
-               if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) {
+               if (domain_type_is_vm(domain)) {
                        iommu_detach_dependent_devices(info->iommu, info->dev);
-                       /* clear this iommu in iommu_bmp, update iommu count
-                        * and capabilities
-                        */
-                       spin_lock_irqsave(&domain->iommu_lock, flags2);
-                       if (test_and_clear_bit(info->iommu->seq_id,
-                                              domain->iommu_bmp)) {
-                               domain->iommu_count--;
-                               domain_update_iommu_cap(domain);
-                       }
-                       spin_unlock_irqrestore(&domain->iommu_lock, flags2);
+                       domain_detach_iommu(domain, info->iommu);
                }
 
                free_devinfo_mem(info);
@@ -2181,8 +2189,6 @@ static struct dmar_domain *dmar_insert_dev_info(struct intel_iommu *iommu,
        info->dev = dev;
        info->domain = domain;
        info->iommu = iommu;
-       if (!dev)
-               domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES;
 
        spin_lock_irqsave(&device_domain_lock, flags);
        if (dev)
@@ -2209,79 +2215,86 @@ static struct dmar_domain *dmar_insert_dev_info(struct intel_iommu *iommu,
        return domain;
 }
 
+static int get_last_alias(struct pci_dev *pdev, u16 alias, void *opaque)
+{
+       *(u16 *)opaque = alias;
+       return 0;
+}
+
 /* domain is initialized */
 static struct dmar_domain *get_domain_for_dev(struct device *dev, int gaw)
 {
-       struct dmar_domain *domain, *free = NULL;
-       struct intel_iommu *iommu = NULL;
+       struct dmar_domain *domain, *tmp;
+       struct intel_iommu *iommu;
        struct device_domain_info *info;
-       struct pci_dev *dev_tmp = NULL;
+       u16 dma_alias;
        unsigned long flags;
-       u8 bus, devfn, bridge_bus, bridge_devfn;
+       u8 bus, devfn;
 
        domain = find_domain(dev);
        if (domain)
                return domain;
 
+       iommu = device_to_iommu(dev, &bus, &devfn);
+       if (!iommu)
+               return NULL;
+
        if (dev_is_pci(dev)) {
                struct pci_dev *pdev = to_pci_dev(dev);
-               u16 segment;
 
-               segment = pci_domain_nr(pdev->bus);
-               dev_tmp = pci_find_upstream_pcie_bridge(pdev);
-               if (dev_tmp) {
-                       if (pci_is_pcie(dev_tmp)) {
-                               bridge_bus = dev_tmp->subordinate->number;
-                               bridge_devfn = 0;
-                       } else {
-                               bridge_bus = dev_tmp->bus->number;
-                               bridge_devfn = dev_tmp->devfn;
-                       }
-                       spin_lock_irqsave(&device_domain_lock, flags);
-                       info = dmar_search_domain_by_dev_info(segment,
-                                                             bridge_bus,
-                                                             bridge_devfn);
-                       if (info) {
-                               iommu = info->iommu;
-                               domain = info->domain;
-                       }
-                       spin_unlock_irqrestore(&device_domain_lock, flags);
-                       /* pcie-pci bridge already has a domain, uses it */
-                       if (info)
-                               goto found_domain;
+               pci_for_each_dma_alias(pdev, get_last_alias, &dma_alias);
+
+               spin_lock_irqsave(&device_domain_lock, flags);
+               info = dmar_search_domain_by_dev_info(pci_domain_nr(pdev->bus),
+                                                     PCI_BUS_NUM(dma_alias),
+                                                     dma_alias & 0xff);
+               if (info) {
+                       iommu = info->iommu;
+                       domain = info->domain;
                }
-       }
+               spin_unlock_irqrestore(&device_domain_lock, flags);
 
-       iommu = device_to_iommu(dev, &bus, &devfn);
-       if (!iommu)
-               goto error;
+               /* DMA alias already has a domain, uses it */
+               if (info)
+                       goto found_domain;
+       }
 
        /* Allocate and initialize new domain for the device */
-       domain = alloc_domain(false);
+       domain = alloc_domain(0);
        if (!domain)
-               goto error;
-       if (iommu_attach_domain(domain, iommu)) {
+               return NULL;
+       domain->id = iommu_attach_domain(domain, iommu);
+       if (domain->id < 0) {
                free_domain_mem(domain);
-               domain = NULL;
-               goto error;
+               return NULL;
        }
-       free = domain;
-       if (domain_init(domain, gaw))
-               goto error;
+       domain_attach_iommu(domain, iommu);
+       if (domain_init(domain, gaw)) {
+               domain_exit(domain);
+               return NULL;
+       }
+
+       /* register PCI DMA alias device */
+       if (dev_is_pci(dev)) {
+               tmp = dmar_insert_dev_info(iommu, PCI_BUS_NUM(dma_alias),
+                                          dma_alias & 0xff, NULL, domain);
+
+               if (!tmp || tmp != domain) {
+                       domain_exit(domain);
+                       domain = tmp;
+               }
 
-       /* register pcie-to-pci device */
-       if (dev_tmp) {
-               domain = dmar_insert_dev_info(iommu, bridge_bus, bridge_devfn,
-                                             NULL, domain);
                if (!domain)
-                       goto error;
+                       return NULL;
        }
 
 found_domain:
-       domain = dmar_insert_dev_info(iommu, bus, devfn, dev, domain);
-error:
-       if (free != domain)
-               domain_exit(free);
+       tmp = dmar_insert_dev_info(iommu, bus, devfn, dev, domain);
+
+       if (!tmp || tmp != domain) {
+               domain_exit(domain);
+               domain = tmp;
+       }
 
        return domain;
 }
@@ -2405,6 +2418,7 @@ static inline void iommu_prepare_isa(void)
                printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; "
                       "floppy might not work\n");
 
+       pci_dev_put(pdev);
 }
 #else
 static inline void iommu_prepare_isa(void)
@@ -2420,19 +2434,25 @@ static int __init si_domain_init(int hw)
        struct dmar_drhd_unit *drhd;
        struct intel_iommu *iommu;
        int nid, ret = 0;
+       bool first = true;
 
-       si_domain = alloc_domain(false);
+       si_domain = alloc_domain(DOMAIN_FLAG_STATIC_IDENTITY);
        if (!si_domain)
                return -EFAULT;
 
-       si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY;
-
        for_each_active_iommu(iommu, drhd) {
                ret = iommu_attach_domain(si_domain, iommu);
-               if (ret) {
+               if (ret < 0) {
+                       domain_exit(si_domain);
+                       return -EFAULT;
+               } else if (first) {
+                       si_domain->id = ret;
+                       first = false;
+               } else if (si_domain->id != ret) {
                        domain_exit(si_domain);
                        return -EFAULT;
                }
+               domain_attach_iommu(si_domain, iommu);
        }
 
        if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
@@ -2523,22 +2543,46 @@ static bool device_has_rmrr(struct device *dev)
        return false;
 }
 
+/*
+ * There are a couple cases where we need to restrict the functionality of
+ * devices associated with RMRRs.  The first is when evaluating a device for
+ * identity mapping because problems exist when devices are moved in and out
+ * of domains and their respective RMRR information is lost.  This means that
+ * a device with associated RMRRs will never be in a "passthrough" domain.
+ * The second is use of the device through the IOMMU API.  This interface
+ * expects to have full control of the IOVA space for the device.  We cannot
+ * satisfy both the requirement that RMRR access is maintained and have an
+ * unencumbered IOVA space.  We also have no ability to quiesce the device's
+ * use of the RMRR space or even inform the IOMMU API user of the restriction.
+ * We therefore prevent devices associated with an RMRR from participating in
+ * the IOMMU API, which eliminates them from device assignment.
+ *
+ * In both cases we assume that PCI USB devices with RMRRs have them largely
+ * for historical reasons and that the RMRR space is not actively used post
+ * boot.  This exclusion may change if vendors begin to abuse it.
+ */
+static bool device_is_rmrr_locked(struct device *dev)
+{
+       if (!device_has_rmrr(dev))
+               return false;
+
+       if (dev_is_pci(dev)) {
+               struct pci_dev *pdev = to_pci_dev(dev);
+
+               if ((pdev->class >> 8) == PCI_CLASS_SERIAL_USB)
+                       return false;
+       }
+
+       return true;
+}
+
 static int iommu_should_identity_map(struct device *dev, int startup)
 {
 
        if (dev_is_pci(dev)) {
                struct pci_dev *pdev = to_pci_dev(dev);
 
-               /*
-                * We want to prevent any device associated with an RMRR from
-                * getting placed into the SI Domain. This is done because
-                * problems exist when devices are moved in and out of domains
-                * and their respective RMRR info is lost. We exempt USB devices
-                * from this process due to their usage of RMRRs that are known
-                * to not be needed after BIOS hand-off to OS.
-                */
-               if (device_has_rmrr(dev) &&
-                   (pdev->class >> 8) != PCI_CLASS_SERIAL_USB)
+               if (device_is_rmrr_locked(dev))
                        return 0;
 
                if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
@@ -2850,11 +2894,7 @@ static int __init init_dmars(void)
 
                iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
                iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
-
-               ret = iommu_enable_translation(iommu);
-               if (ret)
-                       goto free_iommu;
-
+               iommu_enable_translation(iommu);
                iommu_disable_protect_mem_regions(iommu);
        }
 
@@ -3091,10 +3131,10 @@ static void flush_unmaps(void)
                        /* On real hardware multiple invalidations are expensive */
                        if (cap_caching_mode(iommu->cap))
                                iommu_flush_iotlb_psi(iommu, domain->id,
-                                       iova->pfn_lo, iova->pfn_hi - iova->pfn_lo + 1,
+                                       iova->pfn_lo, iova_size(iova),
                                        !deferred_flush[i].freelist[j], 0);
                        else {
-                               mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
+                               mask = ilog2(mm_to_dma_pfn(iova_size(iova)));
                                iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
                                                (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
                        }
@@ -3144,9 +3184,7 @@ static void add_unmap(struct dmar_domain *dom, struct iova *iova, struct page *f
        spin_unlock_irqrestore(&async_umap_flush_lock, flags);
 }
 
-static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
-                            size_t size, enum dma_data_direction dir,
-                            struct dma_attrs *attrs)
+static void intel_unmap(struct device *dev, dma_addr_t dev_addr)
 {
        struct dmar_domain *domain;
        unsigned long start_pfn, last_pfn;
@@ -3190,6 +3228,13 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
        }
 }
 
+static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
+                            size_t size, enum dma_data_direction dir,
+                            struct dma_attrs *attrs)
+{
+       intel_unmap(dev, dev_addr);
+}
+
 static void *intel_alloc_coherent(struct device *dev, size_t size,
                                  dma_addr_t *dma_handle, gfp_t flags,
                                  struct dma_attrs *attrs)
@@ -3246,7 +3291,7 @@ static void intel_free_coherent(struct device *dev, size_t size, void *vaddr,
        size = PAGE_ALIGN(size);
        order = get_order(size);
 
-       intel_unmap_page(dev, dma_handle, size, DMA_BIDIRECTIONAL, NULL);
+       intel_unmap(dev, dma_handle);
        if (!dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT))
                __free_pages(page, order);
 }
@@ -3255,43 +3300,7 @@ static void intel_unmap_sg(struct device *dev, struct scatterlist *sglist,
                           int nelems, enum dma_data_direction dir,
                           struct dma_attrs *attrs)
 {
-       struct dmar_domain *domain;
-       unsigned long start_pfn, last_pfn;
-       struct iova *iova;
-       struct intel_iommu *iommu;
-       struct page *freelist;
-
-       if (iommu_no_mapping(dev))
-               return;
-
-       domain = find_domain(dev);
-       BUG_ON(!domain);
-
-       iommu = domain_get_iommu(domain);
-
-       iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
-       if (WARN_ONCE(!iova, "Driver unmaps unmatched sglist at PFN %llx\n",
-                     (unsigned long long)sglist[0].dma_address))
-               return;
-
-       start_pfn = mm_to_dma_pfn(iova->pfn_lo);
-       last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
-
-       freelist = domain_unmap(domain, start_pfn, last_pfn);
-
-       if (intel_iommu_strict) {
-               iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
-                                     last_pfn - start_pfn + 1, !freelist, 0);
-               /* free iova */
-               __free_iova(&domain->iovad, iova);
-               dma_free_pagelist(freelist);
-       } else {
-               add_unmap(domain, iova, freelist);
-               /*
-                * queue up the release of the unmap to save the 1/6th of the
-                * cpu used up by the iotlb flush operation...
-                */
-       }
+       intel_unmap(dev, sglist[0].dma_address);
 }
 
 static int intel_nontranslate_map_sg(struct device *hddev,
@@ -3355,13 +3364,8 @@ static int intel_map_sg(struct device *dev, struct scatterlist *sglist, int nele
 
        ret = domain_sg_mapping(domain, start_vpfn, sglist, size, prot);
        if (unlikely(ret)) {
-               /*  clear the page */
-               dma_pte_clear_range(domain, start_vpfn,
-                                   start_vpfn + size - 1);
-               /* free page tables */
                dma_pte_free_pagetable(domain, start_vpfn,
                                       start_vpfn + size - 1);
-               /* free iova */
                __free_iova(&domain->iovad, iova);
                return 0;
        }
@@ -3568,10 +3572,8 @@ static int init_iommu_hw(void)
 
                iommu->flush.flush_context(iommu, 0, 0, 0,
                                           DMA_CCMD_GLOBAL_INVL);
-               iommu->flush.flush_iotlb(iommu, 0, 0, 0,
-                                        DMA_TLB_GLOBAL_FLUSH);
-               if (iommu_enable_translation(iommu))
-                       return 1;
+               iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
+               iommu_enable_translation(iommu);
                iommu_disable_protect_mem_regions(iommu);
        }
 
@@ -3873,9 +3875,7 @@ static int device_notifier(struct notifier_block *nb,
 
        down_read(&dmar_global_lock);
        domain_remove_one_dev_info(domain, dev);
-       if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
-           !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) &&
-           list_empty(&domain->devices))
+       if (!domain_type_is_vm_or_si(domain) && list_empty(&domain->devices))
                domain_exit(domain);
        up_read(&dmar_global_lock);
 
@@ -3935,8 +3935,7 @@ static int intel_iommu_memory_notifier(struct notifier_block *nb,
                        rcu_read_lock();
                        for_each_active_iommu(iommu, drhd)
                                iommu_flush_iotlb_psi(iommu, si_domain->id,
-                                       iova->pfn_lo,
-                                       iova->pfn_hi - iova->pfn_lo + 1,
+                                       iova->pfn_lo, iova_size(iova),
                                        !freelist, 0);
                        rcu_read_unlock();
                        dma_free_pagelist(freelist);
@@ -3955,6 +3954,63 @@ static struct notifier_block intel_iommu_memory_nb = {
        .priority = 0
 };
 
+
+static ssize_t intel_iommu_show_version(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct intel_iommu *iommu = dev_get_drvdata(dev);
+       u32 ver = readl(iommu->reg + DMAR_VER_REG);
+       return sprintf(buf, "%d:%d\n",
+                      DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver));
+}
+static DEVICE_ATTR(version, S_IRUGO, intel_iommu_show_version, NULL);
+
+static ssize_t intel_iommu_show_address(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct intel_iommu *iommu = dev_get_drvdata(dev);
+       return sprintf(buf, "%llx\n", iommu->reg_phys);
+}
+static DEVICE_ATTR(address, S_IRUGO, intel_iommu_show_address, NULL);
+
+static ssize_t intel_iommu_show_cap(struct device *dev,
+                                   struct device_attribute *attr,
+                                   char *buf)
+{
+       struct intel_iommu *iommu = dev_get_drvdata(dev);
+       return sprintf(buf, "%llx\n", iommu->cap);
+}
+static DEVICE_ATTR(cap, S_IRUGO, intel_iommu_show_cap, NULL);
+
+static ssize_t intel_iommu_show_ecap(struct device *dev,
+                                   struct device_attribute *attr,
+                                   char *buf)
+{
+       struct intel_iommu *iommu = dev_get_drvdata(dev);
+       return sprintf(buf, "%llx\n", iommu->ecap);
+}
+static DEVICE_ATTR(ecap, S_IRUGO, intel_iommu_show_ecap, NULL);
+
+static struct attribute *intel_iommu_attrs[] = {
+       &dev_attr_version.attr,
+       &dev_attr_address.attr,
+       &dev_attr_cap.attr,
+       &dev_attr_ecap.attr,
+       NULL,
+};
+
+static struct attribute_group intel_iommu_group = {
+       .name = "intel-iommu",
+       .attrs = intel_iommu_attrs,
+};
+
+const struct attribute_group *intel_iommu_groups[] = {
+       &intel_iommu_group,
+       NULL,
+};
+
 int __init intel_iommu_init(void)
 {
        int ret = -ENODEV;
@@ -4026,6 +4082,11 @@ int __init intel_iommu_init(void)
 
        init_iommu_pm_ops();
 
+       for_each_active_iommu(iommu, drhd)
+               iommu->iommu_dev = iommu_device_create(NULL, iommu,
+                                                      intel_iommu_groups,
+                                                      iommu->name);
+
        bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
        bus_register_notifier(&pci_bus_type, &device_nb);
        if (si_domain && !hw_pass_through)
@@ -4044,33 +4105,27 @@ out_free_dmar:
        return ret;
 }
 
+static int iommu_detach_dev_cb(struct pci_dev *pdev, u16 alias, void *opaque)
+{
+       struct intel_iommu *iommu = opaque;
+
+       iommu_detach_dev(iommu, PCI_BUS_NUM(alias), alias & 0xff);
+       return 0;
+}
+
+/*
+ * NB - intel-iommu lacks any sort of reference counting for the users of
+ * dependent devices.  If multiple endpoints have intersecting dependent
+ * devices, unbinding the driver from any one of them will possibly leave
+ * the others unable to operate.
+ */
 static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
                                           struct device *dev)
 {
-       struct pci_dev *tmp, *parent, *pdev;
-
        if (!iommu || !dev || !dev_is_pci(dev))
                return;
 
-       pdev = to_pci_dev(dev);
-
-       /* dependent device detach */
-       tmp = pci_find_upstream_pcie_bridge(pdev);
-       /* Secondary interface's bus number and devfn 0 */
-       if (tmp) {
-               parent = pdev->bus->self;
-               while (parent != tmp) {
-                       iommu_detach_dev(iommu, parent->bus->number,
-                                        parent->devfn);
-                       parent = parent->bus->self;
-               }
-               if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
-                       iommu_detach_dev(iommu,
-                               tmp->subordinate->number, 0);
-               else /* this is a legacy PCI bridge */
-                       iommu_detach_dev(iommu, tmp->bus->number,
-                                        tmp->devfn);
-       }
+       pci_for_each_dma_alias(to_pci_dev(dev), &iommu_detach_dev_cb, iommu);
 }
 
 static void domain_remove_one_dev_info(struct dmar_domain *domain,
@@ -4117,20 +4172,9 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain,
        spin_unlock_irqrestore(&device_domain_lock, flags);
 
        if (found == 0) {
-               unsigned long tmp_flags;
-               spin_lock_irqsave(&domain->iommu_lock, tmp_flags);
-               clear_bit(iommu->seq_id, domain->iommu_bmp);
-               domain->iommu_count--;
-               domain_update_iommu_cap(domain);
-               spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
-
-               if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
-                   !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)) {
-                       spin_lock_irqsave(&iommu->lock, tmp_flags);
-                       clear_bit(domain->id, iommu->domain_ids);
-                       iommu->domains[domain->id] = NULL;
-                       spin_unlock_irqrestore(&iommu->lock, tmp_flags);
-               }
+               domain_detach_iommu(domain, iommu);
+               if (!domain_type_is_vm_or_si(domain))
+                       iommu_detach_domain(domain, iommu);
        }
 }
 
@@ -4150,7 +4194,6 @@ static int md_domain_init(struct dmar_domain *domain, int guest_width)
        domain->iommu_snooping = 0;
        domain->iommu_superpage = 0;
        domain->max_addr = 0;
-       domain->nid = -1;
 
        /* always allocate the top pgd */
        domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
@@ -4164,7 +4207,7 @@ static int intel_iommu_domain_init(struct iommu_domain *domain)
 {
        struct dmar_domain *dmar_domain;
 
-       dmar_domain = alloc_domain(true);
+       dmar_domain = alloc_domain(DOMAIN_FLAG_VIRTUAL_MACHINE);
        if (!dmar_domain) {
                printk(KERN_ERR
                        "intel_iommu_domain_init: dmar_domain == NULL\n");
@@ -4202,14 +4245,18 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,
        int addr_width;
        u8 bus, devfn;
 
+       if (device_is_rmrr_locked(dev)) {
+               dev_warn(dev, "Device is ineligible for IOMMU domain attach due to platform RMRR requirement.  Contact your platform vendor.\n");
+               return -EPERM;
+       }
+
        /* normally dev is not mapped */
        if (unlikely(domain_context_mapped(dev))) {
                struct dmar_domain *old_domain;
 
                old_domain = find_domain(dev);
                if (old_domain) {
-                       if (dmar_domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
-                           dmar_domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)
+                       if (domain_type_is_vm_or_si(dmar_domain))
                                domain_remove_one_dev_info(old_domain, dev);
                        else
                                domain_remove_dev_info(old_domain);
@@ -4373,99 +4420,42 @@ static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
        return 0;
 }
 
-#define REQ_ACS_FLAGS  (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)
-
 static int intel_iommu_add_device(struct device *dev)
 {
-       struct pci_dev *pdev = to_pci_dev(dev);
-       struct pci_dev *bridge, *dma_pdev = NULL;
+       struct intel_iommu *iommu;
        struct iommu_group *group;
-       int ret;
        u8 bus, devfn;
 
-       if (!device_to_iommu(dev, &bus, &devfn))
+       iommu = device_to_iommu(dev, &bus, &devfn);
+       if (!iommu)
                return -ENODEV;
 
-       bridge = pci_find_upstream_pcie_bridge(pdev);
-       if (bridge) {
-               if (pci_is_pcie(bridge))
-                       dma_pdev = pci_get_domain_bus_and_slot(
-                                               pci_domain_nr(pdev->bus),
-                                               bridge->subordinate->number, 0);
-               if (!dma_pdev)
-                       dma_pdev = pci_dev_get(bridge);
-       } else
-               dma_pdev = pci_dev_get(pdev);
-
-       /* Account for quirked devices */
-       swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));
+       iommu_device_link(iommu->iommu_dev, dev);
 
-       /*
-        * If it's a multifunction device that does not support our
-        * required ACS flags, add to the same group as lowest numbered
-        * function that also does not suport the required ACS flags.
-        */
-       if (dma_pdev->multifunction &&
-           !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) {
-               u8 i, slot = PCI_SLOT(dma_pdev->devfn);
-
-               for (i = 0; i < 8; i++) {
-                       struct pci_dev *tmp;
+       group = iommu_group_get_for_dev(dev);
 
-                       tmp = pci_get_slot(dma_pdev->bus, PCI_DEVFN(slot, i));
-                       if (!tmp)
-                               continue;
-
-                       if (!pci_acs_enabled(tmp, REQ_ACS_FLAGS)) {
-                               swap_pci_ref(&dma_pdev, tmp);
-                               break;
-                       }
-                       pci_dev_put(tmp);
-               }
-       }
-
-       /*
-        * Devices on the root bus go through the iommu.  If that's not us,
-        * find the next upstream device and test ACS up to the root bus.
-        * Finding the next device may require skipping virtual buses.
-        */
-       while (!pci_is_root_bus(dma_pdev->bus)) {
-               struct pci_bus *bus = dma_pdev->bus;
-
-               while (!bus->self) {
-                       if (!pci_is_root_bus(bus))
-                               bus = bus->parent;
-                       else
-                               goto root_bus;
-               }
-
-               if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS))
-                       break;
-
-               swap_pci_ref(&dma_pdev, pci_dev_get(bus->self));
-       }
-
-root_bus:
-       group = iommu_group_get(&dma_pdev->dev);
-       pci_dev_put(dma_pdev);
-       if (!group) {
-               group = iommu_group_alloc();
-               if (IS_ERR(group))
-                       return PTR_ERR(group);
-       }
-
-       ret = iommu_group_add_device(group, dev);
+       if (IS_ERR(group))
+               return PTR_ERR(group);
 
        iommu_group_put(group);
-       return ret;
+       return 0;
 }
 
 static void intel_iommu_remove_device(struct device *dev)
 {
+       struct intel_iommu *iommu;
+       u8 bus, devfn;
+
+       iommu = device_to_iommu(dev, &bus, &devfn);
+       if (!iommu)
+               return;
+
        iommu_group_remove_device(dev);
+
+       iommu_device_unlink(iommu->iommu_dev, dev);
 }
 
-static struct iommu_ops intel_iommu_ops = {
+static const struct iommu_ops intel_iommu_ops = {
        .domain_init    = intel_iommu_domain_init,
        .domain_destroy = intel_iommu_domain_destroy,
        .attach_dev     = intel_iommu_attach_device,