vtd: More TLB flush fixes.

- Made the non-present flush testing a bit simpler.
 - Removed dma_addr_level_page_maddr().  Use a modified
   addr_to_dma_page_maddr() instead.
 - Upon mapping new context entry: flush old entry using domid 0 and
   always flush iotlb.

Signed-off-by: Espen Skoglund <espen.skoglund@netronome.com>
This commit is contained in:
Keir Fraser committed 2008-05-28 16:14:10 +01:00
1 parent 491c0ade25
commit 8a02aa347f
1 file changed
+17 -52
+17 -52
View File
@@ -191,7 +191,7 @@ static int device_context_mapped(struct iommu *iommu, u8 bus, u8 devfn)
return ret;
}
static u64 addr_to_dma_page_maddr(struct domain *domain, u64 addr)
static u64 addr_to_dma_page_maddr(struct domain *domain, u64 addr, int alloc)
{
struct hvm_iommu *hd = domain_hvm_iommu(domain);
struct acpi_drhd_unit *drhd;
@@ -201,7 +201,7 @@ static u64 addr_to_dma_page_maddr(struct domain *domain, u64 addr)
int level = agaw_to_level(hd->agaw);
int offset;
unsigned long flags;
u64 pte_maddr = 0;
u64 pte_maddr = 0, maddr;
u64 *vaddr = NULL;
drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
@@ -211,6 +211,8 @@ static u64 addr_to_dma_page_maddr(struct domain *domain, u64 addr)
spin_lock_irqsave(&hd->mapping_lock, flags);
if ( hd->pgd_maddr == 0 )
{
if ( !alloc )
return 0;
hd->pgd_maddr = alloc_pgtable_maddr();
if ( hd->pgd_maddr == 0 )
return 0;
@@ -224,7 +226,9 @@ static u64 addr_to_dma_page_maddr(struct domain *domain, u64 addr)
if ( dma_pte_addr(*pte) == 0 )
{
u64 maddr = alloc_pgtable_maddr();
if ( !alloc )
break;
maddr = alloc_pgtable_maddr();
dma_set_pte_addr(*pte, maddr);
vaddr = map_vtd_domain_page(maddr);
if ( !vaddr )
@@ -263,41 +267,6 @@ static u64 addr_to_dma_page_maddr(struct domain *domain, u64 addr)
return pte_maddr;
}
/* return address's page at specific level */
static u64 dma_addr_level_page_maddr(
struct domain *domain, u64 addr, int level)
{
struct hvm_iommu *hd = domain_hvm_iommu(domain);
struct dma_pte *parent, *pte = NULL;
int total = agaw_to_level(hd->agaw);
int offset;
u64 pg_maddr = hd->pgd_maddr;
if ( pg_maddr == 0 )
return 0;
parent = (struct dma_pte *)map_vtd_domain_page(pg_maddr);
while ( level <= total )
{
offset = address_level_offset(addr, total);
pte = &parent[offset];
if ( dma_pte_addr(*pte) == 0 )
break;
pg_maddr = pte->val & PAGE_MASK_4K;
unmap_vtd_domain_page(parent);
if ( level == total )
return pg_maddr;
parent = map_vtd_domain_page(pte->val);
total--;
}
unmap_vtd_domain_page(parent);
return 0;
}
static void iommu_flush_write_buffer(struct iommu *iommu)
{
u32 val;
@@ -584,7 +553,7 @@ static void dma_pte_clear_one(struct domain *domain, u64 addr)
drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
/* get last level pte */
pg_maddr = dma_addr_level_page_maddr(domain, addr, 2);
pg_maddr = addr_to_dma_page_maddr(domain, addr, 0);
if ( pg_maddr == 0 )
return;
page = (struct dma_pte *)map_vtd_domain_page(pg_maddr);
@@ -1193,13 +1162,11 @@ static int domain_context_mapping_one(
unmap_vtd_domain_page(context_entries);
/* it's a non-present to present mapping */
if ( iommu_flush_context_device(iommu, domain_iommu_domid(domain),
(((u16)bus) << 8) | devfn,
DMA_CCMD_MASK_NOBIT, 1) )
/* Context entry was previously non-present (with domid 0). */
iommu_flush_context_device(iommu, 0, (((u16)bus) << 8) | devfn,
DMA_CCMD_MASK_NOBIT, 1);
if ( iommu_flush_iotlb_dsi(iommu, 0, 1) )
iommu_flush_write_buffer(iommu);
else
iommu_flush_iotlb_dsi(iommu, 0, 0);
set_bit(iommu->index, &hd->iommu_bitmap);
spin_unlock_irqrestore(&iommu->lock, flags);
@@ -1540,7 +1507,7 @@ int intel_iommu_map_page(
return 0;
#endif
pg_maddr = addr_to_dma_page_maddr(d, (paddr_t)gfn << PAGE_SHIFT_4K);
pg_maddr = addr_to_dma_page_maddr(d, (paddr_t)gfn << PAGE_SHIFT_4K, 1);
if ( pg_maddr == 0 )
return -ENOMEM;
page = (struct dma_pte *)map_vtd_domain_page(pg_maddr);
@@ -1558,11 +1525,9 @@ int intel_iommu_map_page(
if ( !test_bit(iommu->index, &hd->iommu_bitmap) )
continue;
if ( pte_present )
iommu_flush_iotlb_psi(iommu, domain_iommu_domid(d),
(paddr_t)gfn << PAGE_SHIFT_4K, 1, 0);
else if ( iommu_flush_iotlb_psi(iommu, domain_iommu_domid(d),
(paddr_t)gfn << PAGE_SHIFT_4K, 1, 1) )
if ( iommu_flush_iotlb_psi(iommu, domain_iommu_domid(d),
(paddr_t)gfn << PAGE_SHIFT_4K, 1,
!pte_present) )
iommu_flush_write_buffer(iommu);
}
@@ -1609,7 +1574,7 @@ int iommu_page_mapping(struct domain *domain, paddr_t iova,
index = 0;
while ( start_pfn < end_pfn )
{
pg_maddr = addr_to_dma_page_maddr(domain, iova + PAGE_SIZE_4K * index);
pg_maddr = addr_to_dma_page_maddr(domain, iova + PAGE_SIZE_4K*index, 1);
if ( pg_maddr == 0 )
return -ENOMEM;
page = (struct dma_pte *)map_vtd_domain_page(pg_maddr);
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.