x86/amd-iommu: Workaround for erratum 63
[safe/jmp/linux-2.6] / arch / x86 / kernel / amd_iommu.c
index d434a97..f95dfe5 100644 (file)
 #include <linux/pci.h>
 #include <linux/gfp.h>
 #include <linux/bitops.h>
+#include <linux/debugfs.h>
 #include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
 #include <linux/iommu-helper.h>
+#include <linux/iommu.h>
 #include <asm/proto.h>
 #include <asm/iommu.h>
 #include <asm/gart.h>
@@ -38,6 +41,10 @@ static DEFINE_RWLOCK(amd_iommu_devtable_lock);
 static LIST_HEAD(iommu_pd_list);
 static DEFINE_SPINLOCK(iommu_pd_list_lock);
 
+#ifdef CONFIG_IOMMU_API
+static struct iommu_ops amd_iommu_ops;
+#endif
+
 /*
  * general struct to manage commands send to an IOMMU
  */
@@ -47,6 +54,77 @@ struct iommu_cmd {
 
 static int dma_ops_unity_map(struct dma_ops_domain *dma_dom,
                             struct unity_map_entry *e);
+static struct dma_ops_domain *find_protection_domain(u16 devid);
+static u64* alloc_pte(struct protection_domain *dom,
+                     unsigned long address, u64
+                     **pte_page, gfp_t gfp);
+static void dma_ops_reserve_addresses(struct dma_ops_domain *dom,
+                                     unsigned long start_page,
+                                     unsigned int pages);
+
+#ifndef BUS_NOTIFY_UNBOUND_DRIVER
+#define BUS_NOTIFY_UNBOUND_DRIVER 0x0005
+#endif
+
+#ifdef CONFIG_AMD_IOMMU_STATS
+
+/*
+ * Initialization code for statistics collection
+ */
+
+DECLARE_STATS_COUNTER(compl_wait);
+DECLARE_STATS_COUNTER(cnt_map_single);
+DECLARE_STATS_COUNTER(cnt_unmap_single);
+DECLARE_STATS_COUNTER(cnt_map_sg);
+DECLARE_STATS_COUNTER(cnt_unmap_sg);
+DECLARE_STATS_COUNTER(cnt_alloc_coherent);
+DECLARE_STATS_COUNTER(cnt_free_coherent);
+DECLARE_STATS_COUNTER(cross_page);
+DECLARE_STATS_COUNTER(domain_flush_single);
+DECLARE_STATS_COUNTER(domain_flush_all);
+DECLARE_STATS_COUNTER(alloced_io_mem);
+DECLARE_STATS_COUNTER(total_map_requests);
+
+static struct dentry *stats_dir;
+static struct dentry *de_isolate;
+static struct dentry *de_fflush;
+
+static void amd_iommu_stats_add(struct __iommu_counter *cnt)
+{
+       if (stats_dir == NULL)
+               return;
+
+       cnt->dent = debugfs_create_u64(cnt->name, 0444, stats_dir,
+                                      &cnt->value);
+}
+
+static void amd_iommu_stats_init(void)
+{
+       stats_dir = debugfs_create_dir("amd-iommu", NULL);
+       if (stats_dir == NULL)
+               return;
+
+       de_isolate = debugfs_create_bool("isolation", 0444, stats_dir,
+                                        (u32 *)&amd_iommu_isolate);
+
+       de_fflush  = debugfs_create_bool("fullflush", 0444, stats_dir,
+                                        (u32 *)&amd_iommu_unmap_flush);
+
+       amd_iommu_stats_add(&compl_wait);
+       amd_iommu_stats_add(&cnt_map_single);
+       amd_iommu_stats_add(&cnt_unmap_single);
+       amd_iommu_stats_add(&cnt_map_sg);
+       amd_iommu_stats_add(&cnt_unmap_sg);
+       amd_iommu_stats_add(&cnt_alloc_coherent);
+       amd_iommu_stats_add(&cnt_free_coherent);
+       amd_iommu_stats_add(&cross_page);
+       amd_iommu_stats_add(&domain_flush_single);
+       amd_iommu_stats_add(&domain_flush_all);
+       amd_iommu_stats_add(&alloced_io_mem);
+       amd_iommu_stats_add(&total_map_requests);
+}
+
+#endif
 
 /* returns !0 if the IOMMU is caching non-present entries in its TLB */
 static int iommu_has_npcache(struct amd_iommu *iommu)
@@ -144,7 +222,7 @@ irqreturn_t amd_iommu_int_handler(int irq, void *data)
 {
        struct amd_iommu *iommu;
 
-       list_for_each_entry(iommu, &amd_iommu_list, list)
+       for_each_iommu(iommu)
                iommu_poll_events(iommu);
 
        return IRQ_HANDLED;
@@ -188,12 +266,56 @@ static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd)
 
        spin_lock_irqsave(&iommu->lock, flags);
        ret = __iommu_queue_command(iommu, cmd);
+       if (!ret)
+               iommu->need_sync = true;
        spin_unlock_irqrestore(&iommu->lock, flags);
 
        return ret;
 }
 
 /*
+ * This function waits until an IOMMU has completed a completion
+ * wait command
+ */
+static void __iommu_wait_for_completion(struct amd_iommu *iommu)
+{
+       int ready = 0;
+       unsigned status = 0;
+       unsigned long i = 0;
+
+       INC_STATS_COUNTER(compl_wait);
+
+       while (!ready && (i < EXIT_LOOP_COUNT)) {
+               ++i;
+               /* wait for the bit to become one */
+               status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
+               ready = status & MMIO_STATUS_COM_WAIT_INT_MASK;
+       }
+
+       /* set bit back to zero */
+       status &= ~MMIO_STATUS_COM_WAIT_INT_MASK;
+       writel(status, iommu->mmio_base + MMIO_STATUS_OFFSET);
+
+       if (unlikely(i == EXIT_LOOP_COUNT))
+               panic("AMD IOMMU: Completion wait loop failed\n");
+}
+
+/*
+ * This function queues a completion wait command into the command
+ * buffer of an IOMMU
+ */
+static int __iommu_completion_wait(struct amd_iommu *iommu)
+{
+       struct iommu_cmd cmd;
+
+        memset(&cmd, 0, sizeof(cmd));
+        cmd.data[0] = CMD_COMPL_WAIT_INT_MASK;
+        CMD_SET_TYPE(&cmd, CMD_COMPL_WAIT);
+
+        return __iommu_queue_command(iommu, &cmd);
+}
+
+/*
  * This function is called whenever we need to ensure that the IOMMU has
  * completed execution of all commands we sent. It sends a
  * COMPLETION_WAIT command and waits for it to finish. The IOMMU informs
@@ -202,37 +324,23 @@ static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd)
  */
 static int iommu_completion_wait(struct amd_iommu *iommu)
 {
-       int ret = 0, ready = 0;
-       unsigned status = 0;
-       struct iommu_cmd cmd;
-       unsigned long flags, i = 0;
+       int ret = 0;
+       unsigned long flags;
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.data[0] = CMD_COMPL_WAIT_INT_MASK;
-       CMD_SET_TYPE(&cmd, CMD_COMPL_WAIT);
+       spin_lock_irqsave(&iommu->lock, flags);
 
-       iommu->need_sync = 0;
+       if (!iommu->need_sync)
+               goto out;
 
-       spin_lock_irqsave(&iommu->lock, flags);
+       ret = __iommu_completion_wait(iommu);
 
-       ret = __iommu_queue_command(iommu, &cmd);
+       iommu->need_sync = false;
 
        if (ret)
                goto out;
 
-       while (!ready && (i < EXIT_LOOP_COUNT)) {
-               ++i;
-               /* wait for the bit to become one */
-               status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
-               ready = status & MMIO_STATUS_COM_WAIT_INT_MASK;
-       }
+       __iommu_wait_for_completion(iommu);
 
-       /* set bit back to zero */
-       status &= ~MMIO_STATUS_COM_WAIT_INT_MASK;
-       writel(status, iommu->mmio_base + MMIO_STATUS_OFFSET);
-
-       if (unlikely((i == EXIT_LOOP_COUNT) && printk_ratelimit()))
-               printk(KERN_WARNING "AMD IOMMU: Completion wait loop failed\n");
 out:
        spin_unlock_irqrestore(&iommu->lock, flags);
 
@@ -255,11 +363,24 @@ static int iommu_queue_inv_dev_entry(struct amd_iommu *iommu, u16 devid)
 
        ret = iommu_queue_command(iommu, &cmd);
 
-       iommu->need_sync = 1;
-
        return ret;
 }
 
+static void __iommu_build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address,
+                                         u16 domid, int pde, int s)
+{
+       memset(cmd, 0, sizeof(*cmd));
+       address &= PAGE_MASK;
+       CMD_SET_TYPE(cmd, CMD_INV_IOMMU_PAGES);
+       cmd->data[1] |= domid;
+       cmd->data[2] = lower_32_bits(address);
+       cmd->data[3] = upper_32_bits(address);
+       if (s) /* size bit - we flush more than one 4kb page */
+               cmd->data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK;
+       if (pde) /* PDE bit - we wan't flush everything not only the PTEs */
+               cmd->data[2] |= CMD_INV_IOMMU_PAGES_PDE_MASK;
+}
+
 /*
  * Generic command send function for invalidaing TLB entries
  */
@@ -269,21 +390,10 @@ static int iommu_queue_inv_iommu_pages(struct amd_iommu *iommu,
        struct iommu_cmd cmd;
        int ret;
 
-       memset(&cmd, 0, sizeof(cmd));
-       address &= PAGE_MASK;
-       CMD_SET_TYPE(&cmd, CMD_INV_IOMMU_PAGES);
-       cmd.data[1] |= domid;
-       cmd.data[2] = lower_32_bits(address);
-       cmd.data[3] = upper_32_bits(address);
-       if (s) /* size bit - we flush more than one 4kb page */
-               cmd.data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK;
-       if (pde) /* PDE bit - we wan't flush everything not only the PTEs */
-               cmd.data[2] |= CMD_INV_IOMMU_PAGES_PDE_MASK;
+       __iommu_build_inv_iommu_pages(&cmd, address, domid, pde, s);
 
        ret = iommu_queue_command(iommu, &cmd);
 
-       iommu->need_sync = 1;
-
        return ret;
 }
 
@@ -319,9 +429,74 @@ static void iommu_flush_tlb(struct amd_iommu *iommu, u16 domid)
 {
        u64 address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS;
 
+       INC_STATS_COUNTER(domain_flush_single);
+
        iommu_queue_inv_iommu_pages(iommu, address, domid, 0, 1);
 }
 
+/* Flush the whole IO/TLB for a given protection domain - including PDE */
+static void iommu_flush_tlb_pde(struct amd_iommu *iommu, u16 domid)
+{
+       u64 address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS;
+
+       INC_STATS_COUNTER(domain_flush_single);
+
+       iommu_queue_inv_iommu_pages(iommu, address, domid, 1, 1);
+}
+
+/*
+ * This function is used to flush the IO/TLB for a given protection domain
+ * on every IOMMU in the system
+ */
+static void iommu_flush_domain(u16 domid)
+{
+       unsigned long flags;
+       struct amd_iommu *iommu;
+       struct iommu_cmd cmd;
+
+       INC_STATS_COUNTER(domain_flush_all);
+
+       __iommu_build_inv_iommu_pages(&cmd, CMD_INV_IOMMU_ALL_PAGES_ADDRESS,
+                                     domid, 1, 1);
+
+       for_each_iommu(iommu) {
+               spin_lock_irqsave(&iommu->lock, flags);
+               __iommu_queue_command(iommu, &cmd);
+               __iommu_completion_wait(iommu);
+               __iommu_wait_for_completion(iommu);
+               spin_unlock_irqrestore(&iommu->lock, flags);
+       }
+}
+
+void amd_iommu_flush_all_domains(void)
+{
+       int i;
+
+       for (i = 1; i < MAX_DOMAIN_ID; ++i) {
+               if (!test_bit(i, amd_iommu_pd_alloc_bitmap))
+                       continue;
+               iommu_flush_domain(i);
+       }
+}
+
+void amd_iommu_flush_all_devices(void)
+{
+       struct amd_iommu *iommu;
+       int i;
+
+       for (i = 0; i <= amd_iommu_last_bdf; ++i) {
+               if (amd_iommu_pd_table[i] == NULL)
+                       continue;
+
+               iommu = amd_iommu_rlookup_table[i];
+               if (!iommu)
+                       continue;
+
+               iommu_queue_inv_dev_entry(iommu, i);
+               iommu_completion_wait(iommu);
+       }
+}
+
 /****************************************************************************
  *
  * The functions below are used the create the page table mappings for
@@ -336,41 +511,21 @@ static void iommu_flush_tlb(struct amd_iommu *iommu, u16 domid)
  * supporting all features of AMD IOMMU page tables like level skipping
  * and full 64 bit address spaces.
  */
-static int iommu_map(struct protection_domain *dom,
-                    unsigned long bus_addr,
-                    unsigned long phys_addr,
-                    int prot)
+static int iommu_map_page(struct protection_domain *dom,
+                         unsigned long bus_addr,
+                         unsigned long phys_addr,
+                         int prot)
 {
-       u64 __pte, *pte, *page;
+       u64 __pte, *pte;
 
        bus_addr  = PAGE_ALIGN(bus_addr);
-       phys_addr = PAGE_ALIGN(bus_addr);
+       phys_addr = PAGE_ALIGN(phys_addr);
 
        /* only support 512GB address spaces for now */
        if (bus_addr > IOMMU_MAP_SIZE_L3 || !(prot & IOMMU_PROT_MASK))
                return -EINVAL;
 
-       pte = &dom->pt_root[IOMMU_PTE_L2_INDEX(bus_addr)];
-
-       if (!IOMMU_PTE_PRESENT(*pte)) {
-               page = (u64 *)get_zeroed_page(GFP_KERNEL);
-               if (!page)
-                       return -ENOMEM;
-               *pte = IOMMU_L2_PDE(virt_to_phys(page));
-       }
-
-       pte = IOMMU_PTE_PAGE(*pte);
-       pte = &pte[IOMMU_PTE_L1_INDEX(bus_addr)];
-
-       if (!IOMMU_PTE_PRESENT(*pte)) {
-               page = (u64 *)get_zeroed_page(GFP_KERNEL);
-               if (!page)
-                       return -ENOMEM;
-               *pte = IOMMU_L1_PDE(virt_to_phys(page));
-       }
-
-       pte = IOMMU_PTE_PAGE(*pte);
-       pte = &pte[IOMMU_PTE_L0_INDEX(bus_addr)];
+       pte = alloc_pte(dom, bus_addr, NULL, GFP_KERNEL);
 
        if (IOMMU_PTE_PRESENT(*pte))
                return -EBUSY;
@@ -386,6 +541,28 @@ static int iommu_map(struct protection_domain *dom,
        return 0;
 }
 
+static void iommu_unmap_page(struct protection_domain *dom,
+                            unsigned long bus_addr)
+{
+       u64 *pte;
+
+       pte = &dom->pt_root[IOMMU_PTE_L2_INDEX(bus_addr)];
+
+       if (!IOMMU_PTE_PRESENT(*pte))
+               return;
+
+       pte = IOMMU_PTE_PAGE(*pte);
+       pte = &pte[IOMMU_PTE_L1_INDEX(bus_addr)];
+
+       if (!IOMMU_PTE_PRESENT(*pte))
+               return;
+
+       pte = IOMMU_PTE_PAGE(*pte);
+       pte = &pte[IOMMU_PTE_L1_INDEX(bus_addr)];
+
+       *pte = 0;
+}
+
 /*
  * This function checks if a specific unity mapping entry is needed for
  * this specific IOMMU.
@@ -438,7 +615,7 @@ static int dma_ops_unity_map(struct dma_ops_domain *dma_dom,
 
        for (addr = e->address_start; addr < e->address_end;
             addr += PAGE_SIZE) {
-               ret = iommu_map(&dma_dom->domain, addr, addr, e->prot);
+               ret = iommu_map_page(&dma_dom->domain, addr, addr, e->prot);
                if (ret)
                        return ret;
                /*
@@ -446,7 +623,8 @@ static int dma_ops_unity_map(struct dma_ops_domain *dma_dom,
                 * as allocated in the aperture
                 */
                if (addr < dma_dom->aperture_size)
-                       __set_bit(addr >> PAGE_SHIFT, dma_dom->bitmap);
+                       __set_bit(addr >> PAGE_SHIFT,
+                                 dma_dom->aperture[0]->bitmap);
        }
 
        return 0;
@@ -483,42 +661,191 @@ static int init_unity_mappings_for_device(struct dma_ops_domain *dma_dom,
  ****************************************************************************/
 
 /*
- * The address allocator core function.
+ * The address allocator core functions.
  *
  * called with domain->lock held
  */
+
+/*
+ * This function checks if there is a PTE for a given dma address. If
+ * there is one, it returns the pointer to it.
+ */
+static u64* fetch_pte(struct protection_domain *domain,
+                     unsigned long address)
+{
+       u64 *pte;
+
+       pte = &domain->pt_root[IOMMU_PTE_L2_INDEX(address)];
+
+       if (!IOMMU_PTE_PRESENT(*pte))
+               return NULL;
+
+       pte = IOMMU_PTE_PAGE(*pte);
+       pte = &pte[IOMMU_PTE_L1_INDEX(address)];
+
+       if (!IOMMU_PTE_PRESENT(*pte))
+               return NULL;
+
+       pte = IOMMU_PTE_PAGE(*pte);
+       pte = &pte[IOMMU_PTE_L0_INDEX(address)];
+
+       return pte;
+}
+
+/*
+ * This function is used to add a new aperture range to an existing
+ * aperture in case of dma_ops domain allocation or address allocation
+ * failure.
+ */
+static int alloc_new_range(struct amd_iommu *iommu,
+                          struct dma_ops_domain *dma_dom,
+                          bool populate, gfp_t gfp)
+{
+       int index = dma_dom->aperture_size >> APERTURE_RANGE_SHIFT;
+       int i;
+
+#ifdef CONFIG_IOMMU_STRESS
+       populate = false;
+#endif
+
+       if (index >= APERTURE_MAX_RANGES)
+               return -ENOMEM;
+
+       dma_dom->aperture[index] = kzalloc(sizeof(struct aperture_range), gfp);
+       if (!dma_dom->aperture[index])
+               return -ENOMEM;
+
+       dma_dom->aperture[index]->bitmap = (void *)get_zeroed_page(gfp);
+       if (!dma_dom->aperture[index]->bitmap)
+               goto out_free;
+
+       dma_dom->aperture[index]->offset = dma_dom->aperture_size;
+
+       if (populate) {
+               unsigned long address = dma_dom->aperture_size;
+               int i, num_ptes = APERTURE_RANGE_PAGES / 512;
+               u64 *pte, *pte_page;
+
+               for (i = 0; i < num_ptes; ++i) {
+                       pte = alloc_pte(&dma_dom->domain, address,
+                                       &pte_page, gfp);
+                       if (!pte)
+                               goto out_free;
+
+                       dma_dom->aperture[index]->pte_pages[i] = pte_page;
+
+                       address += APERTURE_RANGE_SIZE / 64;
+               }
+       }
+
+       dma_dom->aperture_size += APERTURE_RANGE_SIZE;
+
+       /* Intialize the exclusion range if necessary */
+       if (iommu->exclusion_start &&
+           iommu->exclusion_start >= dma_dom->aperture[index]->offset &&
+           iommu->exclusion_start < dma_dom->aperture_size) {
+               unsigned long startpage = iommu->exclusion_start >> PAGE_SHIFT;
+               int pages = iommu_num_pages(iommu->exclusion_start,
+                                           iommu->exclusion_length,
+                                           PAGE_SIZE);
+               dma_ops_reserve_addresses(dma_dom, startpage, pages);
+       }
+
+       /*
+        * Check for areas already mapped as present in the new aperture
+        * range and mark those pages as reserved in the allocator. Such
+        * mappings may already exist as a result of requested unity
+        * mappings for devices.
+        */
+       for (i = dma_dom->aperture[index]->offset;
+            i < dma_dom->aperture_size;
+            i += PAGE_SIZE) {
+               u64 *pte = fetch_pte(&dma_dom->domain, i);
+               if (!pte || !IOMMU_PTE_PRESENT(*pte))
+                       continue;
+
+               dma_ops_reserve_addresses(dma_dom, i << PAGE_SHIFT, 1);
+       }
+
+       return 0;
+
+out_free:
+       free_page((unsigned long)dma_dom->aperture[index]->bitmap);
+
+       kfree(dma_dom->aperture[index]);
+       dma_dom->aperture[index] = NULL;
+
+       return -ENOMEM;
+}
+
+static unsigned long dma_ops_area_alloc(struct device *dev,
+                                       struct dma_ops_domain *dom,
+                                       unsigned int pages,
+                                       unsigned long align_mask,
+                                       u64 dma_mask,
+                                       unsigned long start)
+{
+       unsigned long next_bit = dom->next_address % APERTURE_RANGE_SIZE;
+       int max_index = dom->aperture_size >> APERTURE_RANGE_SHIFT;
+       int i = start >> APERTURE_RANGE_SHIFT;
+       unsigned long boundary_size;
+       unsigned long address = -1;
+       unsigned long limit;
+
+       next_bit >>= PAGE_SHIFT;
+
+       boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
+                       PAGE_SIZE) >> PAGE_SHIFT;
+
+       for (;i < max_index; ++i) {
+               unsigned long offset = dom->aperture[i]->offset >> PAGE_SHIFT;
+
+               if (dom->aperture[i]->offset >= dma_mask)
+                       break;
+
+               limit = iommu_device_max_index(APERTURE_RANGE_PAGES, offset,
+                                              dma_mask >> PAGE_SHIFT);
+
+               address = iommu_area_alloc(dom->aperture[i]->bitmap,
+                                          limit, next_bit, pages, 0,
+                                           boundary_size, align_mask);
+               if (address != -1) {
+                       address = dom->aperture[i]->offset +
+                                 (address << PAGE_SHIFT);
+                       dom->next_address = address + (pages << PAGE_SHIFT);
+                       break;
+               }
+
+               next_bit = 0;
+       }
+
+       return address;
+}
+
 static unsigned long dma_ops_alloc_addresses(struct device *dev,
                                             struct dma_ops_domain *dom,
                                             unsigned int pages,
                                             unsigned long align_mask,
                                             u64 dma_mask)
 {
-       unsigned long limit;
        unsigned long address;
-       unsigned long boundary_size;
 
-       boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
-                       PAGE_SIZE) >> PAGE_SHIFT;
-       limit = iommu_device_max_index(dom->aperture_size >> PAGE_SHIFT, 0,
-                                      dma_mask >> PAGE_SHIFT);
+#ifdef CONFIG_IOMMU_STRESS
+       dom->next_address = 0;
+       dom->need_flush = true;
+#endif
 
-       if (dom->next_bit >= limit) {
-               dom->next_bit = 0;
-               dom->need_flush = true;
-       }
+       address = dma_ops_area_alloc(dev, dom, pages, align_mask,
+                                    dma_mask, dom->next_address);
 
-       address = iommu_area_alloc(dom->bitmap, limit, dom->next_bit, pages,
-                                  0 , boundary_size, align_mask);
        if (address == -1) {
-               address = iommu_area_alloc(dom->bitmap, limit, 0, pages,
-                               0, boundary_size, align_mask);
+               dom->next_address = 0;
+               address = dma_ops_area_alloc(dev, dom, pages, align_mask,
+                                            dma_mask, 0);
                dom->need_flush = true;
        }
 
-       if (likely(address != -1)) {
-               dom->next_bit = address + pages;
-               address <<= PAGE_SHIFT;
-       } else
+       if (unlikely(address == -1))
                address = bad_dma_address;
 
        WARN_ON((address + (PAGE_SIZE*pages)) > dom->aperture_size);
@@ -535,11 +862,23 @@ static void dma_ops_free_addresses(struct dma_ops_domain *dom,
                                   unsigned long address,
                                   unsigned int pages)
 {
-       address >>= PAGE_SHIFT;
-       iommu_area_free(dom->bitmap, address, pages);
+       unsigned i = address >> APERTURE_RANGE_SHIFT;
+       struct aperture_range *range = dom->aperture[i];
+
+       BUG_ON(i >= APERTURE_MAX_RANGES || range == NULL);
+
+#ifdef CONFIG_IOMMU_STRESS
+       if (i < 4)
+               return;
+#endif
 
-       if (address >= dom->next_bit)
+       if (address >= dom->next_address)
                dom->need_flush = true;
+
+       address = (address % APERTURE_RANGE_SIZE) >> PAGE_SHIFT;
+
+       iommu_area_free(range->bitmap, address, pages);
+
 }
 
 /****************************************************************************
@@ -569,6 +908,16 @@ static u16 domain_id_alloc(void)
        return id;
 }
 
+static void domain_id_free(int id)
+{
+       unsigned long flags;
+
+       write_lock_irqsave(&amd_iommu_devtable_lock, flags);
+       if (id > 0 && id < MAX_DOMAIN_ID)
+               __clear_bit(id, amd_iommu_pd_alloc_bitmap);
+       write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
+}
+
 /*
  * Used to reserve address ranges in the aperture (e.g. for exclusion
  * ranges.
@@ -577,20 +926,24 @@ static void dma_ops_reserve_addresses(struct dma_ops_domain *dom,
                                      unsigned long start_page,
                                      unsigned int pages)
 {
-       unsigned int last_page = dom->aperture_size >> PAGE_SHIFT;
+       unsigned int i, last_page = dom->aperture_size >> PAGE_SHIFT;
 
        if (start_page + pages > last_page)
                pages = last_page - start_page;
 
-       iommu_area_reserve(dom->bitmap, start_page, pages);
+       for (i = start_page; i < start_page + pages; ++i) {
+               int index = i / APERTURE_RANGE_PAGES;
+               int page  = i % APERTURE_RANGE_PAGES;
+               __set_bit(page, dom->aperture[index]->bitmap);
+       }
 }
 
-static void dma_ops_free_pagetable(struct dma_ops_domain *dma_dom)
+static void free_pagetable(struct protection_domain *domain)
 {
        int i, j;
        u64 *p1, *p2, *p3;
 
-       p1 = dma_dom->domain.pt_root;
+       p1 = domain->pt_root;
 
        if (!p1)
                return;
@@ -600,7 +953,7 @@ static void dma_ops_free_pagetable(struct dma_ops_domain *dma_dom)
                        continue;
 
                p2 = IOMMU_PTE_PAGE(p1[i]);
-               for (j = 0; j < 512; ++i) {
+               for (j = 0; j < 512; ++j) {
                        if (!IOMMU_PTE_PRESENT(p2[j]))
                                continue;
                        p3 = IOMMU_PTE_PAGE(p2[j]);
@@ -611,6 +964,8 @@ static void dma_ops_free_pagetable(struct dma_ops_domain *dma_dom)
        }
 
        free_page((unsigned long)p1);
+
+       domain->pt_root = NULL;
 }
 
 /*
@@ -619,14 +974,19 @@ static void dma_ops_free_pagetable(struct dma_ops_domain *dma_dom)
  */
 static void dma_ops_domain_free(struct dma_ops_domain *dom)
 {
+       int i;
+
        if (!dom)
                return;
 
-       dma_ops_free_pagetable(dom);
+       free_pagetable(&dom->domain);
 
-       kfree(dom->pte_pages);
-
-       kfree(dom->bitmap);
+       for (i = 0; i < APERTURE_MAX_RANGES; ++i) {
+               if (!dom->aperture[i])
+                       continue;
+               free_page((unsigned long)dom->aperture[i]->bitmap);
+               kfree(dom->aperture[i]);
+       }
 
        kfree(dom);
 }
@@ -636,19 +996,9 @@ static void dma_ops_domain_free(struct dma_ops_domain *dom)
  * It also intializes the page table and the address allocator data
  * structures required for the dma_ops interface
  */
-static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
-                                                  unsigned order)
+static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu)
 {
        struct dma_ops_domain *dma_dom;
-       unsigned i, num_pte_pages;
-       u64 *l2_pde;
-       u64 address;
-
-       /*
-        * Currently the DMA aperture must be between 32 MB and 1GB in size
-        */
-       if ((order < 25) || (order > 30))
-               return NULL;
 
        dma_dom = kzalloc(sizeof(struct dma_ops_domain), GFP_KERNEL);
        if (!dma_dom)
@@ -661,112 +1011,193 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
                goto free_dma_dom;
        dma_dom->domain.mode = PAGE_MODE_3_LEVEL;
        dma_dom->domain.pt_root = (void *)get_zeroed_page(GFP_KERNEL);
+       dma_dom->domain.flags = PD_DMA_OPS_MASK;
        dma_dom->domain.priv = dma_dom;
        if (!dma_dom->domain.pt_root)
                goto free_dma_dom;
-       dma_dom->aperture_size = (1ULL << order);
-       dma_dom->bitmap = kzalloc(dma_dom->aperture_size / (PAGE_SIZE * 8),
-                                 GFP_KERNEL);
-       if (!dma_dom->bitmap)
-               goto free_dma_dom;
-       /*
-        * mark the first page as allocated so we never return 0 as
-        * a valid dma-address. So we can use 0 as error value
-        */
-       dma_dom->bitmap[0] = 1;
-       dma_dom->next_bit = 0;
 
        dma_dom->need_flush = false;
        dma_dom->target_dev = 0xffff;
 
-       /* Intialize the exclusion range if necessary */
-       if (iommu->exclusion_start &&
-           iommu->exclusion_start < dma_dom->aperture_size) {
-               unsigned long startpage = iommu->exclusion_start >> PAGE_SHIFT;
-               int pages = iommu_num_pages(iommu->exclusion_start,
-                                           iommu->exclusion_length,
-                                           PAGE_SIZE);
-               dma_ops_reserve_addresses(dma_dom, startpage, pages);
-       }
+       if (alloc_new_range(iommu, dma_dom, true, GFP_KERNEL))
+               goto free_dma_dom;
 
        /*
-        * At the last step, build the page tables so we don't need to
-        * allocate page table pages in the dma_ops mapping/unmapping
-        * path.
+        * mark the first page as allocated so we never return 0 as
+        * a valid dma-address. So we can use 0 as error value
         */
-       num_pte_pages = dma_dom->aperture_size / (PAGE_SIZE * 512);
-       dma_dom->pte_pages = kzalloc(num_pte_pages * sizeof(void *),
-                       GFP_KERNEL);
-       if (!dma_dom->pte_pages)
-               goto free_dma_dom;
+       dma_dom->aperture[0]->bitmap[0] = 1;
+       dma_dom->next_address = 0;
 
-       l2_pde = (u64 *)get_zeroed_page(GFP_KERNEL);
-       if (l2_pde == NULL)
-               goto free_dma_dom;
-
-       dma_dom->domain.pt_root[0] = IOMMU_L2_PDE(virt_to_phys(l2_pde));
-
-       for (i = 0; i < num_pte_pages; ++i) {
-               dma_dom->pte_pages[i] = (u64 *)get_zeroed_page(GFP_KERNEL);
-               if (!dma_dom->pte_pages[i])
-                       goto free_dma_dom;
-               address = virt_to_phys(dma_dom->pte_pages[i]);
-               l2_pde[i] = IOMMU_L1_PDE(address);
-       }
 
        return dma_dom;
 
 free_dma_dom:
        dma_ops_domain_free(dma_dom);
 
-       return NULL;
+       return NULL;
+}
+
+/*
+ * little helper function to check whether a given protection domain is a
+ * dma_ops domain
+ */
+static bool dma_ops_domain(struct protection_domain *domain)
+{
+       return domain->flags & PD_DMA_OPS_MASK;
+}
+
+/*
+ * Find out the protection domain structure for a given PCI device. This
+ * will give us the pointer to the page table root for example.
+ */
+static struct protection_domain *domain_for_device(u16 devid)
+{
+       struct protection_domain *dom;
+       unsigned long flags;
+
+       read_lock_irqsave(&amd_iommu_devtable_lock, flags);
+       dom = amd_iommu_pd_table[devid];
+       read_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
+
+       return dom;
+}
+
+/*
+ * If a device is not yet associated with a domain, this function does
+ * assigns it visible for the hardware
+ */
+static void attach_device(struct amd_iommu *iommu,
+                         struct protection_domain *domain,
+                         u16 devid)
+{
+       unsigned long flags;
+       u64 pte_root = virt_to_phys(domain->pt_root);
+
+       domain->dev_cnt += 1;
+
+       pte_root |= (domain->mode & DEV_ENTRY_MODE_MASK)
+                   << DEV_ENTRY_MODE_SHIFT;
+       pte_root |= IOMMU_PTE_IR | IOMMU_PTE_IW | IOMMU_PTE_P | IOMMU_PTE_TV;
+
+       write_lock_irqsave(&amd_iommu_devtable_lock, flags);
+       amd_iommu_dev_table[devid].data[0] = lower_32_bits(pte_root);
+       amd_iommu_dev_table[devid].data[1] = upper_32_bits(pte_root);
+       amd_iommu_dev_table[devid].data[2] = domain->id;
+
+       amd_iommu_pd_table[devid] = domain;
+       write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
+
+       /*
+        * We might boot into a crash-kernel here. The crashed kernel
+        * left the caches in the IOMMU dirty. So we have to flush
+        * here to evict all dirty stuff.
+        */
+       iommu_queue_inv_dev_entry(iommu, devid);
+       iommu_flush_tlb_pde(iommu, domain->id);
+}
+
+/*
+ * Removes a device from a protection domain (unlocked)
+ */
+static void __detach_device(struct protection_domain *domain, u16 devid)
+{
+
+       /* lock domain */
+       spin_lock(&domain->lock);
+
+       /* remove domain from the lookup table */
+       amd_iommu_pd_table[devid] = NULL;
+
+       /* remove entry from the device table seen by the hardware */
+       amd_iommu_dev_table[devid].data[0] = IOMMU_PTE_P | IOMMU_PTE_TV;
+       amd_iommu_dev_table[devid].data[1] = 0;
+       amd_iommu_dev_table[devid].data[2] = 0;
+
+       amd_iommu_apply_erratum_63(devid);
+
+       /* decrease reference counter */
+       domain->dev_cnt -= 1;
+
+       /* ready */
+       spin_unlock(&domain->lock);
 }
 
 /*
- * Find out the protection domain structure for a given PCI device. This
- * will give us the pointer to the page table root for example.
+ * Removes a device from a protection domain (with devtable_lock held)
  */
-static struct protection_domain *domain_for_device(u16 devid)
+static void detach_device(struct protection_domain *domain, u16 devid)
 {
-       struct protection_domain *dom;
        unsigned long flags;
 
-       read_lock_irqsave(&amd_iommu_devtable_lock, flags);
-       dom = amd_iommu_pd_table[devid];
-       read_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
-
-       return dom;
+       /* lock device table */
+       write_lock_irqsave(&amd_iommu_devtable_lock, flags);
+       __detach_device(domain, devid);
+       write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
 }
 
-/*
- * If a device is not yet associated with a domain, this function does
- * assigns it visible for the hardware
- */
-static void set_device_domain(struct amd_iommu *iommu,
-                             struct protection_domain *domain,
-                             u16 devid)
+static int device_change_notifier(struct notifier_block *nb,
+                                 unsigned long action, void *data)
 {
+       struct device *dev = data;
+       struct pci_dev *pdev = to_pci_dev(dev);
+       u16 devid = calc_devid(pdev->bus->number, pdev->devfn);
+       struct protection_domain *domain;
+       struct dma_ops_domain *dma_domain;
+       struct amd_iommu *iommu;
        unsigned long flags;
 
-       u64 pte_root = virt_to_phys(domain->pt_root);
+       if (devid > amd_iommu_last_bdf)
+               goto out;
 
-       pte_root |= (domain->mode & DEV_ENTRY_MODE_MASK)
-                   << DEV_ENTRY_MODE_SHIFT;
-       pte_root |= IOMMU_PTE_IR | IOMMU_PTE_IW | IOMMU_PTE_P | IOMMU_PTE_TV;
+       devid = amd_iommu_alias_table[devid];
 
-       write_lock_irqsave(&amd_iommu_devtable_lock, flags);
-       amd_iommu_dev_table[devid].data[0] = lower_32_bits(pte_root);
-       amd_iommu_dev_table[devid].data[1] = upper_32_bits(pte_root);
-       amd_iommu_dev_table[devid].data[2] = domain->id;
+       iommu = amd_iommu_rlookup_table[devid];
+       if (iommu == NULL)
+               goto out;
 
-       amd_iommu_pd_table[devid] = domain;
-       write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
+       domain = domain_for_device(devid);
+
+       if (domain && !dma_ops_domain(domain))
+               WARN_ONCE(1, "AMD IOMMU WARNING: device %s already bound "
+                         "to a non-dma-ops domain\n", dev_name(dev));
+
+       switch (action) {
+       case BUS_NOTIFY_UNBOUND_DRIVER:
+               if (!domain)
+                       goto out;
+               detach_device(domain, devid);
+               break;
+       case BUS_NOTIFY_ADD_DEVICE:
+               /* allocate a protection domain if a device is added */
+               dma_domain = find_protection_domain(devid);
+               if (dma_domain)
+                       goto out;
+               dma_domain = dma_ops_domain_alloc(iommu);
+               if (!dma_domain)
+                       goto out;
+               dma_domain->target_dev = devid;
+
+               spin_lock_irqsave(&iommu_pd_list_lock, flags);
+               list_add_tail(&dma_domain->list, &iommu_pd_list);
+               spin_unlock_irqrestore(&iommu_pd_list_lock, flags);
+
+               break;
+       default:
+               goto out;
+       }
 
        iommu_queue_inv_dev_entry(iommu, devid);
+       iommu_completion_wait(iommu);
 
-       iommu->need_sync = 1;
+out:
+       return 0;
 }
 
+static struct notifier_block device_nb = {
+       .notifier_call = device_change_notifier,
+};
+
 /*****************************************************************************
  *
  * The next functions belong to the dma_ops mapping/unmapping code.
@@ -802,7 +1233,6 @@ static struct dma_ops_domain *find_protection_domain(u16 devid)
        list_for_each_entry(entry, &iommu_pd_list, list) {
                if (entry->target_dev == devid) {
                        ret = entry;
-                       list_del(&ret->list);
                        break;
                }
        }
@@ -853,16 +1283,78 @@ static int get_device_resources(struct device *dev,
                if (!dma_dom)
                        dma_dom = (*iommu)->default_dom;
                *domain = &dma_dom->domain;
-               set_device_domain(*iommu, *domain, *bdf);
-               printk(KERN_INFO "AMD IOMMU: Using protection domain %d for "
-                               "device ", (*domain)->id);
-               print_devid(_bdf, 1);
+               attach_device(*iommu, *domain, *bdf);
+               DUMP_printk("Using protection domain %d for device %s\n",
+                           (*domain)->id, dev_name(dev));
        }
 
+       if (domain_for_device(_bdf) == NULL)
+               attach_device(*iommu, *domain, _bdf);
+
        return 1;
 }
 
 /*
+ * If the pte_page is not yet allocated this function is called
+ */
+static u64* alloc_pte(struct protection_domain *dom,
+                     unsigned long address, u64 **pte_page, gfp_t gfp)
+{
+       u64 *pte, *page;
+
+       pte = &dom->pt_root[IOMMU_PTE_L2_INDEX(address)];
+
+       if (!IOMMU_PTE_PRESENT(*pte)) {
+               page = (u64 *)get_zeroed_page(gfp);
+               if (!page)
+                       return NULL;
+               *pte = IOMMU_L2_PDE(virt_to_phys(page));
+       }
+
+       pte = IOMMU_PTE_PAGE(*pte);
+       pte = &pte[IOMMU_PTE_L1_INDEX(address)];
+
+       if (!IOMMU_PTE_PRESENT(*pte)) {
+               page = (u64 *)get_zeroed_page(gfp);
+               if (!page)
+                       return NULL;
+               *pte = IOMMU_L1_PDE(virt_to_phys(page));
+       }
+
+       pte = IOMMU_PTE_PAGE(*pte);
+
+       if (pte_page)
+               *pte_page = pte;
+
+       pte = &pte[IOMMU_PTE_L0_INDEX(address)];
+
+       return pte;
+}
+
+/*
+ * This function fetches the PTE for a given address in the aperture
+ */
+static u64* dma_ops_get_pte(struct dma_ops_domain *dom,
+                           unsigned long address)
+{
+       struct aperture_range *aperture;
+       u64 *pte, *pte_page;
+
+       aperture = dom->aperture[APERTURE_RANGE_INDEX(address)];
+       if (!aperture)
+               return NULL;
+
+       pte = aperture->pte_pages[APERTURE_PAGE_INDEX(address)];
+       if (!pte) {
+               pte = alloc_pte(&dom->domain, address, &pte_page, GFP_ATOMIC);
+               aperture->pte_pages[APERTURE_PAGE_INDEX(address)] = pte_page;
+       } else
+               pte += IOMMU_PTE_L0_INDEX(address);
+
+       return pte;
+}
+
+/*
  * This is the generic map function. It maps one 4kb page at paddr to
  * the given address in the DMA address space for the domain.
  */
@@ -878,8 +1370,9 @@ static dma_addr_t dma_ops_domain_map(struct amd_iommu *iommu,
 
        paddr &= PAGE_MASK;
 
-       pte  = dom->pte_pages[IOMMU_PTE_L1_INDEX(address)];
-       pte += IOMMU_PTE_L0_INDEX(address);
+       pte  = dma_ops_get_pte(dom, address);
+       if (!pte)
+               return bad_dma_address;
 
        __pte = paddr | IOMMU_PTE_P | IOMMU_PTE_FC;
 
@@ -904,14 +1397,20 @@ static void dma_ops_domain_unmap(struct amd_iommu *iommu,
                                 struct dma_ops_domain *dom,
                                 unsigned long address)
 {
+       struct aperture_range *aperture;
        u64 *pte;
 
        if (address >= dom->aperture_size)
                return;
 
-       WARN_ON(address & 0xfffULL || address > dom->aperture_size);
+       aperture = dom->aperture[APERTURE_RANGE_INDEX(address)];
+       if (!aperture)
+               return;
+
+       pte  = aperture->pte_pages[APERTURE_PAGE_INDEX(address)];
+       if (!pte)
+               return;
 
-       pte  = dom->pte_pages[IOMMU_PTE_L1_INDEX(address)];
        pte += IOMMU_PTE_L0_INDEX(address);
 
        WARN_ON(!*pte);
@@ -921,8 +1420,8 @@ static void dma_ops_domain_unmap(struct amd_iommu *iommu,
 
 /*
  * This function contains common code for mapping of a physically
- * contiguous memory region into DMA address space. It is uses by all
- * mapping functions provided by this IOMMU driver.
+ * contiguous memory region into DMA address space. It is used by all
+ * mapping functions provided with this IOMMU driver.
  * Must be called with the domain lock held.
  */
 static dma_addr_t __map_single(struct device *dev,
@@ -935,7 +1434,7 @@ static dma_addr_t __map_single(struct device *dev,
                               u64 dma_mask)
 {
        dma_addr_t offset = paddr & ~PAGE_MASK;
-       dma_addr_t address, start;
+       dma_addr_t address, start, ret;
        unsigned int pages;
        unsigned long align_mask = 0;
        int i;
@@ -943,22 +1442,48 @@ static dma_addr_t __map_single(struct device *dev,
        pages = iommu_num_pages(paddr, size, PAGE_SIZE);
        paddr &= PAGE_MASK;
 
+       INC_STATS_COUNTER(total_map_requests);
+
+       if (pages > 1)
+               INC_STATS_COUNTER(cross_page);
+
        if (align)
                align_mask = (1UL << get_order(size)) - 1;
 
+retry:
        address = dma_ops_alloc_addresses(dev, dma_dom, pages, align_mask,
                                          dma_mask);
-       if (unlikely(address == bad_dma_address))
-               goto out;
+       if (unlikely(address == bad_dma_address)) {
+               /*
+                * setting next_address here will let the address
+                * allocator only scan the new allocated range in the
+                * first run. This is a small optimization.
+                */
+               dma_dom->next_address = dma_dom->aperture_size;
+
+               if (alloc_new_range(iommu, dma_dom, false, GFP_ATOMIC))
+                       goto out;
+
+               /*
+                * aperture was sucessfully enlarged by 128 MB, try
+                * allocation again
+                */
+               goto retry;
+       }
 
        start = address;
        for (i = 0; i < pages; ++i) {
-               dma_ops_domain_map(iommu, dma_dom, start, paddr, dir);
+               ret = dma_ops_domain_map(iommu, dma_dom, start, paddr, dir);
+               if (ret == bad_dma_address)
+                       goto out_unmap;
+
                paddr += PAGE_SIZE;
                start += PAGE_SIZE;
        }
        address += offset;
 
+       ADD_STATS_COUNTER(alloced_io_mem, size);
+
        if (unlikely(dma_dom->need_flush && !amd_iommu_unmap_flush)) {
                iommu_flush_tlb(iommu, dma_dom->domain.id);
                dma_dom->need_flush = false;
@@ -967,6 +1492,17 @@ static dma_addr_t __map_single(struct device *dev,
 
 out:
        return address;
+
+out_unmap:
+
+       for (--i; i >= 0; --i) {
+               start -= PAGE_SIZE;
+               dma_ops_domain_unmap(iommu, dma_dom, start);
+       }
+
+       dma_ops_free_addresses(dma_dom, address, pages);
+
+       return bad_dma_address;
 }
 
 /*
@@ -982,7 +1518,8 @@ static void __unmap_single(struct amd_iommu *iommu,
        dma_addr_t i, start;
        unsigned int pages;
 
-       if ((dma_addr == 0) || (dma_addr + size > dma_dom->aperture_size))
+       if ((dma_addr == bad_dma_address) ||
+           (dma_addr + size > dma_dom->aperture_size))
                return;
 
        pages = iommu_num_pages(dma_addr, size, PAGE_SIZE);
@@ -994,6 +1531,8 @@ static void __unmap_single(struct amd_iommu *iommu,
                start += PAGE_SIZE;
        }
 
+       SUB_STATS_COUNTER(alloced_io_mem, size);
+
        dma_ops_free_addresses(dma_dom, dma_addr, pages);
 
        if (amd_iommu_unmap_flush || dma_dom->need_flush) {
@@ -1005,8 +1544,10 @@ static void __unmap_single(struct amd_iommu *iommu,
 /*
  * The exported map_single function for dma_ops.
  */
-static dma_addr_t map_single(struct device *dev, phys_addr_t paddr,
-                            size_t size, int dir)
+static dma_addr_t map_page(struct device *dev, struct page *page,
+                          unsigned long offset, size_t size,
+                          enum dma_data_direction dir,
+                          struct dma_attrs *attrs)
 {
        unsigned long flags;
        struct amd_iommu *iommu;
@@ -1014,6 +1555,9 @@ static dma_addr_t map_single(struct device *dev, phys_addr_t paddr,
        u16 devid;
        dma_addr_t addr;
        u64 dma_mask;
+       phys_addr_t paddr = page_to_phys(page) + offset;
+
+       INC_STATS_COUNTER(cnt_map_single);
 
        if (!check_device(dev))
                return bad_dma_address;
@@ -1026,14 +1570,16 @@ static dma_addr_t map_single(struct device *dev, phys_addr_t paddr,
                /* device not handled by any AMD IOMMU */
                return (dma_addr_t)paddr;
 
+       if (!dma_ops_domain(domain))
+               return bad_dma_address;
+
        spin_lock_irqsave(&domain->lock, flags);
        addr = __map_single(dev, iommu, domain->priv, paddr, size, dir, false,
                            dma_mask);
        if (addr == bad_dma_address)
                goto out;
 
-       if (unlikely(iommu->need_sync))
-               iommu_completion_wait(iommu);
+       iommu_completion_wait(iommu);
 
 out:
        spin_unlock_irqrestore(&domain->lock, flags);
@@ -1044,25 +1590,29 @@ out:
 /*
  * The exported unmap_single function for dma_ops.
  */
-static void unmap_single(struct device *dev, dma_addr_t dma_addr,
-                        size_t size, int dir)
+static void unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
+                      enum dma_data_direction dir, struct dma_attrs *attrs)
 {
        unsigned long flags;
        struct amd_iommu *iommu;
        struct protection_domain *domain;
        u16 devid;
 
+       INC_STATS_COUNTER(cnt_unmap_single);
+
        if (!check_device(dev) ||
            !get_device_resources(dev, &iommu, &domain, &devid))
                /* device not handled by any AMD IOMMU */
                return;
 
+       if (!dma_ops_domain(domain))
+               return;
+
        spin_lock_irqsave(&domain->lock, flags);
 
        __unmap_single(iommu, domain->priv, dma_addr, size, dir);
 
-       if (unlikely(iommu->need_sync))
-               iommu_completion_wait(iommu);
+       iommu_completion_wait(iommu);
 
        spin_unlock_irqrestore(&domain->lock, flags);
 }
@@ -1090,7 +1640,8 @@ static int map_sg_no_iommu(struct device *dev, struct scatterlist *sglist,
  * lists).
  */
 static int map_sg(struct device *dev, struct scatterlist *sglist,
-                 int nelems, int dir)
+                 int nelems, enum dma_data_direction dir,
+                 struct dma_attrs *attrs)
 {
        unsigned long flags;
        struct amd_iommu *iommu;
@@ -1102,6 +1653,8 @@ static int map_sg(struct device *dev, struct scatterlist *sglist,
        int mapped_elems = 0;
        u64 dma_mask;
 
+       INC_STATS_COUNTER(cnt_map_sg);
+
        if (!check_device(dev))
                return 0;
 
@@ -1112,6 +1665,9 @@ static int map_sg(struct device *dev, struct scatterlist *sglist,
        if (!iommu || !domain)
                return map_sg_no_iommu(dev, sglist, nelems, dir);
 
+       if (!dma_ops_domain(domain))
+               return 0;
+
        spin_lock_irqsave(&domain->lock, flags);
 
        for_each_sg(sglist, s, nelems, i) {
@@ -1128,8 +1684,7 @@ static int map_sg(struct device *dev, struct scatterlist *sglist,
                        goto unmap;
        }
 
-       if (unlikely(iommu->need_sync))
-               iommu_completion_wait(iommu);
+       iommu_completion_wait(iommu);
 
 out:
        spin_unlock_irqrestore(&domain->lock, flags);
@@ -1153,7 +1708,8 @@ unmap:
  * lists).
  */
 static void unmap_sg(struct device *dev, struct scatterlist *sglist,
-                    int nelems, int dir)
+                    int nelems, enum dma_data_direction dir,
+                    struct dma_attrs *attrs)
 {
        unsigned long flags;
        struct amd_iommu *iommu;
@@ -1162,10 +1718,15 @@ static void unmap_sg(struct device *dev, struct scatterlist *sglist,
        u16 devid;
        int i;
 
+       INC_STATS_COUNTER(cnt_unmap_sg);
+
        if (!check_device(dev) ||
            !get_device_resources(dev, &iommu, &domain, &devid))
                return;
 
+       if (!dma_ops_domain(domain))
+               return;
+
        spin_lock_irqsave(&domain->lock, flags);
 
        for_each_sg(sglist, s, nelems, i) {
@@ -1174,8 +1735,7 @@ static void unmap_sg(struct device *dev, struct scatterlist *sglist,
                s->dma_address = s->dma_length = 0;
        }
 
-       if (unlikely(iommu->need_sync))
-               iommu_completion_wait(iommu);
+       iommu_completion_wait(iommu);
 
        spin_unlock_irqrestore(&domain->lock, flags);
 }
@@ -1194,6 +1754,8 @@ static void *alloc_coherent(struct device *dev, size_t size,
        phys_addr_t paddr;
        u64 dma_mask = dev->coherent_dma_mask;
 
+       INC_STATS_COUNTER(cnt_alloc_coherent);
+
        if (!check_device(dev))
                return NULL;
 
@@ -1203,7 +1765,7 @@ static void *alloc_coherent(struct device *dev, size_t size,
        flag |= __GFP_ZERO;
        virt_addr = (void *)__get_free_pages(flag, get_order(size));
        if (!virt_addr)
-               return 0;
+               return NULL;
 
        paddr = virt_to_phys(virt_addr);
 
@@ -1212,6 +1774,9 @@ static void *alloc_coherent(struct device *dev, size_t size,
                return virt_addr;
        }
 
+       if (!dma_ops_domain(domain))
+               goto out_free;
+
        if (!dma_mask)
                dma_mask = *dev->dma_mask;
 
@@ -1221,18 +1786,21 @@ static void *alloc_coherent(struct device *dev, size_t size,
                                 size, DMA_BIDIRECTIONAL, true, dma_mask);
 
        if (*dma_addr == bad_dma_address) {
-               free_pages((unsigned long)virt_addr, get_order(size));
-               virt_addr = NULL;
-               goto out;
+               spin_unlock_irqrestore(&domain->lock, flags);
+               goto out_free;
        }
 
-       if (unlikely(iommu->need_sync))
-               iommu_completion_wait(iommu);
+       iommu_completion_wait(iommu);
 
-out:
        spin_unlock_irqrestore(&domain->lock, flags);
 
        return virt_addr;
+
+out_free:
+
+       free_pages((unsigned long)virt_addr, get_order(size));
+
+       return NULL;
 }
 
 /*
@@ -1246,6 +1814,8 @@ static void free_coherent(struct device *dev, size_t size,
        struct protection_domain *domain;
        u16 devid;
 
+       INC_STATS_COUNTER(cnt_free_coherent);
+
        if (!check_device(dev))
                return;
 
@@ -1254,12 +1824,14 @@ static void free_coherent(struct device *dev, size_t size,
        if (!iommu || !domain)
                goto free_mem;
 
+       if (!dma_ops_domain(domain))
+               goto free_mem;
+
        spin_lock_irqsave(&domain->lock, flags);
 
        __unmap_single(iommu, domain->priv, dma_addr, size, DMA_BIDIRECTIONAL);
 
-       if (unlikely(iommu->need_sync))
-               iommu_completion_wait(iommu);
+       iommu_completion_wait(iommu);
 
        spin_unlock_irqrestore(&domain->lock, flags);
 
@@ -1298,16 +1870,15 @@ static int amd_iommu_dma_supported(struct device *dev, u64 mask)
  * we don't need to preallocate the protection domains anymore.
  * For now we have to.
  */
-void prealloc_protection_domains(void)
+static void prealloc_protection_domains(void)
 {
        struct pci_dev *dev = NULL;
        struct dma_ops_domain *dma_dom;
        struct amd_iommu *iommu;
-       int order = amd_iommu_aperture_order;
        u16 devid;
 
        while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
-               devid = (dev->bus->number << 8) | dev->devfn;
+               devid = calc_devid(dev->bus->number, dev->devfn);
                if (devid > amd_iommu_last_bdf)
                        continue;
                devid = amd_iommu_alias_table[devid];
@@ -1316,7 +1887,7 @@ void prealloc_protection_domains(void)
                iommu = amd_iommu_rlookup_table[devid];
                if (!iommu)
                        continue;
-               dma_dom = dma_ops_domain_alloc(iommu, order);
+               dma_dom = dma_ops_domain_alloc(iommu);
                if (!dma_dom)
                        continue;
                init_unity_mappings_for_device(dma_dom, devid);
@@ -1326,11 +1897,11 @@ void prealloc_protection_domains(void)
        }
 }
 
-static struct dma_mapping_ops amd_iommu_dma_ops = {
+static struct dma_map_ops amd_iommu_dma_ops = {
        .alloc_coherent = alloc_coherent,
        .free_coherent = free_coherent,
-       .map_single = map_single,
-       .unmap_single = unmap_single,
+       .map_page = map_page,
+       .unmap_page = unmap_page,
        .map_sg = map_sg,
        .unmap_sg = unmap_sg,
        .dma_supported = amd_iommu_dma_supported,
@@ -1342,7 +1913,6 @@ static struct dma_mapping_ops amd_iommu_dma_ops = {
 int __init amd_iommu_init_dma_ops(void)
 {
        struct amd_iommu *iommu;
-       int order = amd_iommu_aperture_order;
        int ret;
 
        /*
@@ -1350,10 +1920,11 @@ int __init amd_iommu_init_dma_ops(void)
         * found in the system. Devices not assigned to any other
         * protection domain will be assigned to the default one.
         */
-       list_for_each_entry(iommu, &amd_iommu_list, list) {
-               iommu->default_dom = dma_ops_domain_alloc(iommu, order);
+       for_each_iommu(iommu) {
+               iommu->default_dom = dma_ops_domain_alloc(iommu);
                if (iommu->default_dom == NULL)
                        return -ENOMEM;
+               iommu->default_dom->domain.flags |= PD_DEFAULT_MASK;
                ret = iommu_init_unity_mappings(iommu);
                if (ret)
                        goto free_domains;
@@ -1377,14 +1948,248 @@ int __init amd_iommu_init_dma_ops(void)
        /* Make the driver finally visible to the drivers */
        dma_ops = &amd_iommu_dma_ops;
 
+       register_iommu(&amd_iommu_ops);
+
+       bus_register_notifier(&pci_bus_type, &device_nb);
+
+       amd_iommu_stats_init();
+
        return 0;
 
 free_domains:
 
-       list_for_each_entry(iommu, &amd_iommu_list, list) {
+       for_each_iommu(iommu) {
                if (iommu->default_dom)
                        dma_ops_domain_free(iommu->default_dom);
        }
 
        return ret;
 }
+
+/*****************************************************************************
+ *
+ * The following functions belong to the exported interface of AMD IOMMU
+ *
+ * This interface allows access to lower level functions of the IOMMU
+ * like protection domain handling and assignement of devices to domains
+ * which is not possible with the dma_ops interface.
+ *
+ *****************************************************************************/
+
+static void cleanup_domain(struct protection_domain *domain)
+{
+       unsigned long flags;
+       u16 devid;
+
+       write_lock_irqsave(&amd_iommu_devtable_lock, flags);
+
+       for (devid = 0; devid <= amd_iommu_last_bdf; ++devid)
+               if (amd_iommu_pd_table[devid] == domain)
+                       __detach_device(domain, devid);
+
+       write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
+}
+
+static int amd_iommu_domain_init(struct iommu_domain *dom)
+{
+       struct protection_domain *domain;
+
+       domain = kzalloc(sizeof(*domain), GFP_KERNEL);
+       if (!domain)
+               return -ENOMEM;
+
+       spin_lock_init(&domain->lock);
+       domain->mode = PAGE_MODE_3_LEVEL;
+       domain->id = domain_id_alloc();
+       if (!domain->id)
+               goto out_free;
+       domain->pt_root = (void *)get_zeroed_page(GFP_KERNEL);
+       if (!domain->pt_root)
+               goto out_free;
+
+       dom->priv = domain;
+
+       return 0;
+
+out_free:
+       kfree(domain);
+
+       return -ENOMEM;
+}
+
+static void amd_iommu_domain_destroy(struct iommu_domain *dom)
+{
+       struct protection_domain *domain = dom->priv;
+
+       if (!domain)
+               return;
+
+       if (domain->dev_cnt > 0)
+               cleanup_domain(domain);
+
+       BUG_ON(domain->dev_cnt != 0);
+
+       free_pagetable(domain);
+
+       domain_id_free(domain->id);
+
+       kfree(domain);
+
+       dom->priv = NULL;
+}
+
+static void amd_iommu_detach_device(struct iommu_domain *dom,
+                                   struct device *dev)
+{
+       struct protection_domain *domain = dom->priv;
+       struct amd_iommu *iommu;
+       struct pci_dev *pdev;
+       u16 devid;
+
+       if (dev->bus != &pci_bus_type)
+               return;
+
+       pdev = to_pci_dev(dev);
+
+       devid = calc_devid(pdev->bus->number, pdev->devfn);
+
+       if (devid > 0)
+               detach_device(domain, devid);
+
+       iommu = amd_iommu_rlookup_table[devid];
+       if (!iommu)
+               return;
+
+       iommu_queue_inv_dev_entry(iommu, devid);
+       iommu_completion_wait(iommu);
+}
+
+static int amd_iommu_attach_device(struct iommu_domain *dom,
+                                  struct device *dev)
+{
+       struct protection_domain *domain = dom->priv;
+       struct protection_domain *old_domain;
+       struct amd_iommu *iommu;
+       struct pci_dev *pdev;
+       u16 devid;
+
+       if (dev->bus != &pci_bus_type)
+               return -EINVAL;
+
+       pdev = to_pci_dev(dev);
+
+       devid = calc_devid(pdev->bus->number, pdev->devfn);
+
+       if (devid >= amd_iommu_last_bdf ||
+                       devid != amd_iommu_alias_table[devid])
+               return -EINVAL;
+
+       iommu = amd_iommu_rlookup_table[devid];
+       if (!iommu)
+               return -EINVAL;
+
+       old_domain = domain_for_device(devid);
+       if (old_domain)
+               detach_device(old_domain, devid);
+
+       attach_device(iommu, domain, devid);
+
+       iommu_completion_wait(iommu);
+
+       return 0;
+}
+
+static int amd_iommu_map_range(struct iommu_domain *dom,
+                              unsigned long iova, phys_addr_t paddr,
+                              size_t size, int iommu_prot)
+{
+       struct protection_domain *domain = dom->priv;
+       unsigned long i,  npages = iommu_num_pages(paddr, size, PAGE_SIZE);
+       int prot = 0;
+       int ret;
+
+       if (iommu_prot & IOMMU_READ)
+               prot |= IOMMU_PROT_IR;
+       if (iommu_prot & IOMMU_WRITE)
+               prot |= IOMMU_PROT_IW;
+
+       iova  &= PAGE_MASK;
+       paddr &= PAGE_MASK;
+
+       for (i = 0; i < npages; ++i) {
+               ret = iommu_map_page(domain, iova, paddr, prot);
+               if (ret)
+                       return ret;
+
+               iova  += PAGE_SIZE;
+               paddr += PAGE_SIZE;
+       }
+
+       return 0;
+}
+
+static void amd_iommu_unmap_range(struct iommu_domain *dom,
+                                 unsigned long iova, size_t size)
+{
+
+       struct protection_domain *domain = dom->priv;
+       unsigned long i,  npages = iommu_num_pages(iova, size, PAGE_SIZE);
+
+       iova  &= PAGE_MASK;
+
+       for (i = 0; i < npages; ++i) {
+               iommu_unmap_page(domain, iova);
+               iova  += PAGE_SIZE;
+       }
+
+       iommu_flush_domain(domain->id);
+}
+
+static phys_addr_t amd_iommu_iova_to_phys(struct iommu_domain *dom,
+                                         unsigned long iova)
+{
+       struct protection_domain *domain = dom->priv;
+       unsigned long offset = iova & ~PAGE_MASK;
+       phys_addr_t paddr;
+       u64 *pte;
+
+       pte = &domain->pt_root[IOMMU_PTE_L2_INDEX(iova)];
+
+       if (!IOMMU_PTE_PRESENT(*pte))
+               return 0;
+
+       pte = IOMMU_PTE_PAGE(*pte);
+       pte = &pte[IOMMU_PTE_L1_INDEX(iova)];
+
+       if (!IOMMU_PTE_PRESENT(*pte))
+               return 0;
+
+       pte = IOMMU_PTE_PAGE(*pte);
+       pte = &pte[IOMMU_PTE_L0_INDEX(iova)];
+
+       if (!IOMMU_PTE_PRESENT(*pte))
+               return 0;
+
+       paddr  = *pte & IOMMU_PAGE_MASK;
+       paddr |= offset;
+
+       return paddr;
+}
+
+static int amd_iommu_domain_has_cap(struct iommu_domain *domain,
+                                   unsigned long cap)
+{
+       return 0;
+}
+
+static struct iommu_ops amd_iommu_ops = {
+       .domain_init = amd_iommu_domain_init,
+       .domain_destroy = amd_iommu_domain_destroy,
+       .attach_dev = amd_iommu_attach_device,
+       .detach_dev = amd_iommu_detach_device,
+       .map = amd_iommu_map_range,
+       .unmap = amd_iommu_unmap_range,
+       .iova_to_phys = amd_iommu_iova_to_phys,
+       .domain_has_cap = amd_iommu_domain_has_cap,
+};
+