hv: vtd: export iommu_flush_cache

VT-d shares the EPT tables as the second level translation tables.
For the IOMMUs that don't support page-walk coherecy, cpu cache should
be flushed for the IOMMU EPT entries that are modified.

For the current implementation, EPT tables for translating from GPA to HPA
for EPT/IOMMU are not modified after VM is created, so cpu cache invlidation is
done once per VM before starting execution of VM.
However, this may be changed, runtime EPT modification is possible.

When cpu cache of EPT entries is invalidated when modification, there is no need
invalidate cpu cache globally per VM.

This patch exports iommu_flush_cache for EPT entry cache invlidation operations.
- IOMMUs share the same copy of EPT table, cpu cache should be flushed if any of
  the IOMMU active doesn't support page-walk coherency.
- In the context of ACRN, GPA to HPA mapping relationship is not changed after
  VM created, skip flushing iotlb to avoid potential performance penalty.

Tracked-On: #4120
Signed-off-by: Binbin Wu <binbin.wu@intel.com>
Reviewed-by: Anthony Xu <anthony.xu@intel.com>
This commit is contained in:
Binbin Wu
2019-07-01 12:23:15 +08:00
committed by wenlingz
parent 30a773f7b0
commit a6944fe620
3 changed files with 28 additions and 14 deletions

View File

@@ -284,16 +284,18 @@ static inline void dmar_wait_completion(const struct dmar_drhd_rt *dmar_unit, ui
}
}
/* flush cache when root table, context table updated */
static void iommu_flush_cache(const struct dmar_drhd_rt *dmar_unit,
void *p, uint32_t size)
/* Flush CPU cache when root table, context table or second-level translation teable updated
* In the context of ACRN, GPA to HPA mapping relationship is not changed after VM created,
* skip flushing iotlb to avoid performance penalty.
*/
void iommu_flush_cache(const void *p, uint32_t size)
{
uint32_t i;
/* if vtd support page-walk coherency, no need to flush cacheline */
if (iommu_ecap_c(dmar_unit->ecap) == 0U) {
if (!iommu_page_walk_coherent) {
for (i = 0U; i < size; i += CACHE_LINE_SIZE) {
clflush((char *)p + i);
clflush((const char *)p + i);
}
}
}
@@ -1077,7 +1079,7 @@ static int32_t add_iommu_device(struct iommu_domain *domain, uint16_t segment, u
root_entry->hi_64 = 0UL;
root_entry->lo_64 = lo_64;
iommu_flush_cache(dmar_unit, root_entry, sizeof(struct dmar_entry));
iommu_flush_cache(root_entry, sizeof(struct dmar_entry));
} else {
context_table_addr = dmar_get_bitslice(root_entry->lo_64,
ROOT_ENTRY_LOWER_CTP_MASK, ROOT_ENTRY_LOWER_CTP_POS);
@@ -1132,7 +1134,7 @@ static int32_t add_iommu_device(struct iommu_domain *domain, uint16_t segment, u
context_entry->hi_64 = hi_64;
context_entry->lo_64 = lo_64;
iommu_flush_cache(dmar_unit, context_entry, sizeof(struct dmar_entry));
iommu_flush_cache(context_entry, sizeof(struct dmar_entry));
}
}
}
@@ -1181,7 +1183,7 @@ static int32_t remove_iommu_device(const struct iommu_domain *domain, uint16_t s
/* clear the present bit first */
context_entry->lo_64 = 0UL;
context_entry->hi_64 = 0UL;
iommu_flush_cache(dmar_unit, context_entry, sizeof(struct dmar_entry));
iommu_flush_cache(context_entry, sizeof(struct dmar_entry));
sid.bits.b = bus;
sid.bits.d = pci_slot(devfun);
@@ -1370,7 +1372,7 @@ int32_t dmar_assign_irte(struct intr_source intr_src, union dmar_ir_entry irte,
ir_entry->entry.hi_64 = irte.entry.hi_64;
ir_entry->entry.lo_64 = irte.entry.lo_64;
iommu_flush_cache(dmar_unit, ir_entry, sizeof(union dmar_ir_entry));
iommu_flush_cache(ir_entry, sizeof(union dmar_ir_entry));
dmar_invalid_iec(dmar_unit, index, 0U, false);
}
return ret;
@@ -1401,7 +1403,7 @@ void dmar_free_irte(struct intr_source intr_src, uint16_t index)
ir_entry = ir_table + index;
ir_entry->bits.present = 0x0UL;
iommu_flush_cache(dmar_unit, ir_entry, sizeof(union dmar_ir_entry));
iommu_flush_cache(ir_entry, sizeof(union dmar_ir_entry));
dmar_invalid_iec(dmar_unit, index, 0U, false);
}
}