vtd: fix memory coherency issue of vtd table
Acked-by: Kevin Tian
@@ -252,6 +252,20 @@ static void iommu_write64(struct dmar_drhd_rt *dmar_uint, uint32_t offset,
mmio_write_long(temp, dmar_uint->drhd->reg_base_addr + offset + 4);
}
+/* flush cache when root table, context table updated */
+static void iommu_flush_cache(struct dmar_drhd_rt *dmar_uint,
+ void *p, uint32_t size)
+{
+ uint32_t i;
+
+ /* if vtd support page-walk coherency, no need to flush cacheline */
+ if (iommu_ecap_c(dmar_uint->ecap))
+ return;
+
+ for (i = 0; i < size; i += CACHE_LINE_SIZE)
+ clflush((char *)p + i);
+}
+
#if DBG_IOMMU
static void dmar_uint_show_capability(struct dmar_drhd_rt *dmar_uint)
{
@@ -975,6 +989,8 @@ static int add_iommu_device(struct iommu_domain *domain, uint16_t segment,
root_entry->upper = 0;
root_entry->lower = lower;
+ iommu_flush_cache(dmar_uint, root_entry,
+ sizeof(struct dmar_root_entry));
} else {
context_table_addr = DMAR_GET_BITSLICE(root_entry->lower,
ROOT_ENTRY_LOWER_CTP);
@@ -1028,6 +1044,8 @@ static int add_iommu_device(struct iommu_domain *domain, uint16_t segment,
context_entry->upper = upper;
context_entry->lower = lower;
+ iommu_flush_cache(dmar_uint, context_entry,
+ sizeof(struct dmar_context_entry));
return 0;
}
@@ -1072,6 +1090,8 @@ remove_iommu_device(struct iommu_domain *domain, uint16_t segment,
/* clear the present bit first */
context_entry->lower = 0;
context_entry->upper = 0;
+ iommu_flush_cache(dmar_uint, context_entry,
+ sizeof(struct dmar_context_entry));
/* if caching mode is present, need to invalidate translation cache */
/* if(cap_caching_mode(dmar_uint->cap)) { */
