On Fri, 2011-11-18 at 10:15 -0700, Alex Williamson wrote: > A bit heavy handed, but obviously easier. It feels like we could safely > be more strategic, but maybe we'd end up trashing the cache anyway in a > drawn out attempt to flush the context and all page tables. However, do > we actually need a wbinvd_on_all_cpus()? Probably better to trash one > cache than all of them. Thanks, Yes, it would be wbinvd_on_all_cpus(). The page-table-walk code would look something like this... static void flush_domain_ptes(struct dmar_domain *domain) { int level = agaw_to_level(domain->agaw); struct dma_pte *ptelvl[level + 2], *pte; pte = domain->pgd; clflush_cache_range(pte, VTD_PAGE_SIZE); /* Keep the end condition nice and simple... */ ptelvl[level + 1] = NULL; while (pte) { /* BUG_ON(level < 2); */ if (dma_pte_present(pte)) { if (level == 2) { /* Flush the bottom-level page, but no need to process its *contents* any further. */ clflush_cache_range(phys_to_virt(dma_pte_addr(pte)), VTD_PAGE_SIZE); } else if (!(pte->val & DMA_PTE_LARGE_PAGE)) { /* Remember the next PTE at this level; we'll come back to it. */ ptelvl[level] = pte + 1; /* Go down a level and process PTEs there. */ pte = phys_to_virt(dma_pte_addr(pte)); clflush_cache_range(pte, VTD_PAGE_SIZE); level--; continue; } } pte++; /* When we reach the end of a PTE page, go back up to the next level where we came from. */ while (pte && !((unsigned long)pte & ~VTD_PAGE_MASK)) { level++; pte = ptelvl[level]; } } } -- dwmw2
Attachment:
smime.p7s
Description: S/MIME cryptographic signature