intel-iommu: Avoid global flushes with caching mode.
authorNadav Amit <nadav.amit@gmail.com>
Thu, 8 Apr 2010 20:00:41 +0000 (23:00 +0300)
committerDavid Woodhouse <David.Woodhouse@intel.com>
Fri, 9 Apr 2010 14:54:41 +0000 (15:54 +0100)
While it may be efficient on real hardware, emulation of global
invalidations is very expensive as all shadow entries must be examined.
This patch changes the behaviour when caching mode is enabled (which is
the case when IOMMU emulation takes place). In this case, page specific
invalidation is used instead.

Signed-off-by: Nadav Amit <nadav.amit@gmail.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
drivers/pci/intel-iommu.c

index 1880ee06d7010e1c7f11675b2f79988da574cc74..9ce79b1bae8348b6e0e6b7f17b9753c0fcea05b5 100644 (file)
@@ -2647,15 +2647,24 @@ static void flush_unmaps(void)
                if (!deferred_flush[i].next)
                        continue;
 
-               iommu->flush.flush_iotlb(iommu, 0, 0, 0,
+               /* In caching mode, global flushes turn emulation expensive */
+               if (!cap_caching_mode(iommu->cap))
+                       iommu->flush.flush_iotlb(iommu, 0, 0, 0,
                                         DMA_TLB_GLOBAL_FLUSH);
                for (j = 0; j < deferred_flush[i].next; j++) {
                        unsigned long mask;
                        struct iova *iova = deferred_flush[i].iova[j];
-
-                       mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
-                       iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
-                                       (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
+                       struct dmar_domain *domain = deferred_flush[i].domain[j];
+
+                       /* 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, 0);
+                       else {
+                               mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
+                               iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
+                                               (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
+                       }
                        __free_iova(&deferred_flush[i].domain[j]->iovad, iova);
                }
                deferred_flush[i].next = 0;