]> err.no Git - linux-2.6/blobdiff - drivers/pci/intel-iommu.c
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[linux-2.6] / drivers / pci / intel-iommu.c
index 8690a0d45d7fcecd90e07885877454b6dc5e3156..66c0fd21894b155e9db690b65a86bfddffca29c4 100644 (file)
@@ -49,7 +49,7 @@
 
 #define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
 
-#define DMAR_OPERATION_TIMEOUT (HZ*60) /* 1m */
+#define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) /* 10sec */
 
 #define DOMAIN_MAX_ADDR(gaw) ((((u64)1) << gaw) - 1)
 
@@ -59,8 +59,17 @@ static void flush_unmaps_timeout(unsigned long data);
 DEFINE_TIMER(unmap_timer,  flush_unmaps_timeout, 0, 0);
 
 static struct intel_iommu *g_iommus;
+
+#define HIGH_WATER_MARK 250
+struct deferred_flush_tables {
+       int next;
+       struct iova *iova[HIGH_WATER_MARK];
+       struct dmar_domain *domain[HIGH_WATER_MARK];
+};
+
+static struct deferred_flush_tables *deferred_flush;
+
 /* bitmap for indexing intel_iommus */
-static unsigned long   *g_iommus_to_flush;
 static int g_num_of_iommus;
 
 static DEFINE_SPINLOCK(async_umap_flush_lock);
@@ -68,10 +77,6 @@ static LIST_HEAD(unmaps_to_do);
 
 static int timer_on;
 static long list_size;
-static int high_watermark;
-
-static struct dentry *intel_iommu_debug, *debug;
-
 
 static void domain_remove_dev_info(struct dmar_domain *domain);
 
@@ -485,12 +490,12 @@ static int iommu_alloc_root_entry(struct intel_iommu *iommu)
 
 #define IOMMU_WAIT_OP(iommu, offset, op, cond, sts) \
 {\
-       unsigned long start_time = jiffies;\
+       cycles_t start_time = get_cycles();\
        while (1) {\
                sts = op (iommu->reg + offset);\
                if (cond)\
                        break;\
-               if (time_after(jiffies, start_time + DMAR_OPERATION_TIMEOUT))\
+               if (DMAR_OPERATION_TIMEOUT < (get_cycles() - start_time))\
                        panic("DMAR hardware is malfunctioning\n");\
                cpu_relax();\
        }\
@@ -1692,7 +1697,7 @@ int __init init_dmars(void)
        struct dmar_rmrr_unit *rmrr;
        struct pci_dev *pdev;
        struct intel_iommu *iommu;
-       int nlongs, i, ret, unit = 0;
+       int i, ret, unit = 0;
 
        /*
         * for each drhd
@@ -1711,17 +1716,16 @@ int __init init_dmars(void)
                 */
        }
 
-       nlongs = BITS_TO_LONGS(g_num_of_iommus);
-       g_iommus_to_flush = kzalloc(nlongs * sizeof(unsigned long), GFP_KERNEL);
-       if (!g_iommus_to_flush) {
-               printk(KERN_ERR "Intel-IOMMU: "
-                       "Allocating bitmap array failed\n");
-               return -ENOMEM;
-       }
-
        g_iommus = kzalloc(g_num_of_iommus * sizeof(*iommu), GFP_KERNEL);
        if (!g_iommus) {
-               kfree(g_iommus_to_flush);
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       deferred_flush = kzalloc(g_num_of_iommus *
+               sizeof(struct deferred_flush_tables), GFP_KERNEL);
+       if (!deferred_flush) {
+               kfree(g_iommus);
                ret = -ENOMEM;
                goto error;
        }
@@ -1901,32 +1905,31 @@ get_valid_domain_for_dev(struct pci_dev *pdev)
        return domain;
 }
 
-static dma_addr_t intel_map_single(struct device *hwdev, void *addr,
-       size_t size, int dir)
+static dma_addr_t
+intel_map_single(struct device *hwdev, phys_addr_t paddr, size_t size, int dir)
 {
        struct pci_dev *pdev = to_pci_dev(hwdev);
-       int ret;
        struct dmar_domain *domain;
-       unsigned long start_addr;
+       unsigned long start_paddr;
        struct iova *iova;
        int prot = 0;
+       int ret;
 
        BUG_ON(dir == DMA_NONE);
        if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
-               return virt_to_bus(addr);
+               return paddr;
 
        domain = get_valid_domain_for_dev(pdev);
        if (!domain)
                return 0;
 
-       addr = (void *)virt_to_phys(addr);
-       size = aligned_size((u64)addr, size);
+       size = aligned_size((u64)paddr, size);
 
        iova = __intel_alloc_iova(hwdev, domain, size);
        if (!iova)
                goto error;
 
-       start_addr = iova->pfn_lo << PAGE_SHIFT_4K;
+       start_paddr = iova->pfn_lo << PAGE_SHIFT_4K;
 
        /*
         * Check if DMAR supports zero-length reads on write only
@@ -1938,74 +1941,80 @@ static dma_addr_t intel_map_single(struct device *hwdev, void *addr,
        if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
                prot |= DMA_PTE_WRITE;
        /*
-        * addr - (addr + size) might be partial page, we should map the whole
+        * paddr - (paddr + size) might be partial page, we should map the whole
         * page.  Note: if two part of one page are separately mapped, we
-        * might have two guest_addr mapping to the same host addr, but this
+        * might have two guest_addr mapping to the same host paddr, but this
         * is not a big problem
         */
-       ret = domain_page_mapping(domain, start_addr,
-               ((u64)addr) & PAGE_MASK_4K, size, prot);
+       ret = domain_page_mapping(domain, start_paddr,
+               ((u64)paddr) & PAGE_MASK_4K, size, prot);
        if (ret)
                goto error;
 
        pr_debug("Device %s request: %lx@%llx mapping: %lx@%llx, dir %d\n",
-               pci_name(pdev), size, (u64)addr,
-               size, (u64)start_addr, dir);
+               pci_name(pdev), size, (u64)paddr,
+               size, (u64)start_paddr, dir);
 
        /* it's a non-present to present mapping */
        ret = iommu_flush_iotlb_psi(domain->iommu, domain->id,
-                       start_addr, size >> PAGE_SHIFT_4K, 1);
+                       start_paddr, size >> PAGE_SHIFT_4K, 1);
        if (ret)
                iommu_flush_write_buffer(domain->iommu);
 
-       return (start_addr + ((u64)addr & (~PAGE_MASK_4K)));
+       return (start_paddr + ((u64)paddr & (~PAGE_MASK_4K)));
 
 error:
        if (iova)
                __free_iova(&domain->iovad, iova);
        printk(KERN_ERR"Device %s request: %lx@%llx dir %d --- failed\n",
-               pci_name(pdev), size, (u64)addr, dir);
+               pci_name(pdev), size, (u64)paddr, dir);
        return 0;
 }
 
 static void flush_unmaps(void)
 {
-       struct iova *node, *n;
-       unsigned long flags;
-       int i;
+       int i, j;
 
-       spin_lock_irqsave(&async_umap_flush_lock, flags);
        timer_on = 0;
 
        /* just flush them all */
        for (i = 0; i < g_num_of_iommus; i++) {
-               if (test_and_clear_bit(i, g_iommus_to_flush))
+               if (deferred_flush[i].next) {
                        iommu_flush_iotlb_global(&g_iommus[i], 0);
+                       for (j = 0; j < deferred_flush[i].next; j++) {
+                               __free_iova(&deferred_flush[i].domain[j]->iovad,
+                                               deferred_flush[i].iova[j]);
+                       }
+                       deferred_flush[i].next = 0;
+               }
        }
 
-       list_for_each_entry_safe(node, n, &unmaps_to_do, list) {
-               /* free iova */
-               list_del(&node->list);
-               __free_iova(&((struct dmar_domain *)node->dmar)->iovad, node);
-
-       }
        list_size = 0;
-       spin_unlock_irqrestore(&async_umap_flush_lock, flags);
 }
 
 static void flush_unmaps_timeout(unsigned long data)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&async_umap_flush_lock, flags);
        flush_unmaps();
+       spin_unlock_irqrestore(&async_umap_flush_lock, flags);
 }
 
 static void add_unmap(struct dmar_domain *dom, struct iova *iova)
 {
        unsigned long flags;
+       int next, iommu_id;
 
        spin_lock_irqsave(&async_umap_flush_lock, flags);
-       iova->dmar = dom;
-       list_add(&iova->list, &unmaps_to_do);
-       set_bit((dom->iommu - g_iommus), g_iommus_to_flush);
+       if (list_size == HIGH_WATER_MARK)
+               flush_unmaps();
+
+       iommu_id = dom->iommu - g_iommus;
+       next = deferred_flush[iommu_id].next;
+       deferred_flush[iommu_id].domain[next] = dom;
+       deferred_flush[iommu_id].iova[next] = iova;
+       deferred_flush[iommu_id].next++;
 
        if (!timer_on) {
                mod_timer(&unmap_timer, jiffies + msecs_to_jiffies(10));
@@ -2054,8 +2063,6 @@ static void intel_unmap_single(struct device *dev, dma_addr_t dev_addr,
                 * queue up the release of the unmap to save the 1/6th of the
                 * cpu used up by the iotlb flush operation...
                 */
-               if (list_size > high_watermark)
-                       flush_unmaps();
        }
 }
 
@@ -2074,7 +2081,7 @@ static void * intel_alloc_coherent(struct device *hwdev, size_t size,
                return NULL;
        memset(vaddr, 0, size);
 
-       *dma_handle = intel_map_single(hwdev, vaddr, size, DMA_BIDIRECTIONAL);
+       *dma_handle = intel_map_single(hwdev, virt_to_bus(vaddr), size, DMA_BIDIRECTIONAL);
        if (*dma_handle)
                return vaddr;
        free_pages((unsigned long)vaddr, order);
@@ -2380,10 +2387,6 @@ int __init intel_iommu_init(void)
        if (dmar_table_init())
                return  -ENODEV;
 
-       high_watermark = 250;
-       intel_iommu_debug = debugfs_create_dir("intel_iommu", NULL);
-       debug = debugfs_create_u32("high_watermark", S_IWUGO | S_IRUGO,
-                                       intel_iommu_debug, &high_watermark);
        iommu_init_mempool();
        dmar_init_reserved_ranges();