浏览代码

intel-iommu: Avoid global flushes with caching mode.

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>
Nadav Amit 15 年之前
父节点
当前提交
78d5f0f500
共有 1 个文件被更改,包括 14 次插入5 次删除
  1. 14 5
      drivers/pci/intel-iommu.c

+ 14 - 5
drivers/pci/intel-iommu.c

@@ -2647,15 +2647,24 @@ static void flush_unmaps(void)
 		if (!deferred_flush[i].next)
 		if (!deferred_flush[i].next)
 			continue;
 			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);
 					 DMA_TLB_GLOBAL_FLUSH);
 		for (j = 0; j < deferred_flush[i].next; j++) {
 		for (j = 0; j < deferred_flush[i].next; j++) {
 			unsigned long mask;
 			unsigned long mask;
 			struct iova *iova = deferred_flush[i].iova[j];
 			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);
 			__free_iova(&deferred_flush[i].domain[j]->iovad, iova);
 		}
 		}
 		deferred_flush[i].next = 0;
 		deferred_flush[i].next = 0;