@@ -1097,6 +1097,7 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
iommu->segment = drhd->segment;
iommu->node = NUMA_NO_NODE;
+ INIT_LIST_HEAD(&iommu->domains);
ver = readl(iommu->reg + DMAR_VER_REG);
pr_info("%s: reg_base_addr %llx ver %d:%d cap %llx ecap %llx\n",
@@ -1831,6 +1831,7 @@ static int domain_attach_iommu(struct dmar_domain *domain,
goto err_clear;
}
domain_update_iommu_cap(domain);
+ list_add(&domain->domains, &iommu->domains);
spin_unlock(&iommu->lock);
return 0;
@@ -3608,6 +3609,33 @@ static void intel_disable_iommus(void)
iommu_disable_translation(iommu);
}
+void zap_context_table_entries(struct intel_iommu *iommu)
+{
+ struct context_entry *context;
+ struct dmar_domain *domain;
+ struct device_domain_info *device;
+ int bus, devfn;
+ u16 did_old;
+
+ list_for_each_entry(domain, &iommu->domains, domains) {
+ list_for_each_entry(device, &domain->devices, link) {
+ context = iommu_context_addr(iommu, device->bus, device->devfn, 0);
+ if (!context || !context_present(context))
+ continue;
+ context_domain_id(context);
+ context_clear_entry(context);
+ __iommu_flush_cache(iommu, context, sizeof(*context));
+ 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);
+ }
+ }
+}
+
void intel_iommu_shutdown(void)
{
struct dmar_drhd_unit *drhd;
@@ -3620,10 +3648,8 @@ void intel_iommu_shutdown(void)
/* Disable PMRs explicitly here. */
for_each_iommu(iommu, drhd)
- iommu_disable_protect_mem_regions(iommu);
-
- /* Make sure the IOMMUs are switched off */
- intel_disable_iommus();
+ zap_context_table_entries(iommu);
+ return
up_write(&dmar_global_lock);
}
@@ -600,6 +600,7 @@ struct dmar_domain {
spinlock_t lock; /* Protect device tracking lists */
struct list_head devices; /* all devices' list */
struct list_head dev_pasids; /* all attached pasids */
+ struct list_head domains; /* all struct dmar_domains on this IOMMU */
struct dma_pte *pgd; /* virtual address */
int gaw; /* max guest address width */
@@ -700,6 +701,7 @@ struct intel_iommu {
void *perf_statistic;
struct iommu_pmu *pmu;
+ struct list_head domains; /* all struct dmar_domains on this IOMMU */
};
/* PCI domain-device relationship */