]> Git Repo - linux.git/commitdiff
iommu/vt-d: Don't be too aggressive when clearing one context entry
authorFilippo Sironi <[email protected]>
Thu, 31 Aug 2017 08:58:11 +0000 (10:58 +0200)
committerJoerg Roedel <[email protected]>
Fri, 1 Sep 2017 09:30:41 +0000 (11:30 +0200)
Previously, we were invalidating context cache and IOTLB globally when
clearing one context entry.  This is a tad too aggressive.
Invalidate the context cache and IOTLB for the interested device only.

Signed-off-by: Filippo Sironi <[email protected]>
Cc: David Woodhouse <[email protected]>
Cc: David Woodhouse <[email protected]>
Cc: Joerg Roedel <[email protected]>
Cc: Jacob Pan <[email protected]>
Cc: [email protected]
Cc: [email protected]
Acked-by: David Woodhouse <[email protected]>
Signed-off-by: Joerg Roedel <[email protected]>
drivers/iommu/intel-iommu.c

index 695f54ad07cc8935aafe0f902e534e2ee38ad38f..5b112b6a2c9c0ebea986be3bdae1a5e735316c57 100644 (file)
@@ -974,20 +974,6 @@ static int device_context_mapped(struct intel_iommu *iommu, u8 bus, u8 devfn)
        return ret;
 }
 
-static void clear_context_table(struct intel_iommu *iommu, u8 bus, u8 devfn)
-{
-       struct context_entry *context;
-       unsigned long flags;
-
-       spin_lock_irqsave(&iommu->lock, flags);
-       context = iommu_context_addr(iommu, bus, devfn, 0);
-       if (context) {
-               context_clear_entry(context);
-               __iommu_flush_cache(iommu, context, sizeof(*context));
-       }
-       spin_unlock_irqrestore(&iommu->lock, flags);
-}
-
 static void free_context_table(struct intel_iommu *iommu)
 {
        int i;
@@ -2361,13 +2347,33 @@ static inline int domain_pfn_mapping(struct dmar_domain *domain, unsigned long i
 
 static void domain_context_clear_one(struct intel_iommu *iommu, u8 bus, u8 devfn)
 {
+       unsigned long flags;
+       struct context_entry *context;
+       u16 did_old;
+
        if (!iommu)
                return;
 
-       clear_context_table(iommu, bus, devfn);
-       iommu->flush.flush_context(iommu, 0, 0, 0,
-                                          DMA_CCMD_GLOBAL_INVL);
-       iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
+       spin_lock_irqsave(&iommu->lock, flags);
+       context = iommu_context_addr(iommu, bus, devfn, 0);
+       if (!context) {
+               spin_unlock_irqrestore(&iommu->lock, flags);
+               return;
+       }
+       did_old = context_domain_id(context);
+       context_clear_entry(context);
+       __iommu_flush_cache(iommu, context, sizeof(*context));
+       spin_unlock_irqrestore(&iommu->lock, flags);
+       iommu->flush.flush_context(iommu,
+                                  did_old,
+                                  (((u16)bus) << 8) | devfn,
+                                  DMA_CCMD_MASK_NOBIT,
+                                  DMA_CCMD_DEVICE_INVL);
+       iommu->flush.flush_iotlb(iommu,
+                                did_old,
+                                0,
+                                0,
+                                DMA_TLB_DSI_FLUSH);
 }
 
 static inline void unlink_domain_info(struct device_domain_info *info)
This page took 0.068296 seconds and 4 git commands to generate.