Hello,
It seems that intel_iommu_iova_to_phys() doesn't return a correct
physical address for a given iova. This is the latest kernel code for
the function.
static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
dma_addr_t iova)
{
struct dmar_domain *dmar_domain = to_dmar_domain(domain);
struct dma_pte *pte;
int level = 0;
u64 phys = 0;
if (dmar_domain->flags & DOMAIN_FLAG_LOSE_CHILDREN)
return 0;
pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, &level);
if (pte)
phys = dma_pte_addr(pte);
return phys;
}
As it can be seen above, pfn_to_dma_pte() returns PTE for (iova >>
VTD_PAGE_SHIFT). Therefore, I think (iova & (VTD_PAGE_SIZE - 1)) needs
to be added to phys. In addition, I think we need to take into account
level, if it is greater than 1. What do you think about the following
code?
const unsigned long pfn = iova >> VTD_PAGE_SHIFT;
pte = pfn_to_dma_pte(dmar_domain, pfn, &level);
if (pte) {
phys = dma_pte_addr(pte);
if (level > 1)
phys += (pfn & ((level_to_offset_bits(level) << 1) - 1))
<< VTD_PAGE_SHIFT;
phys += (iova & (VTD_PAGE_SIZE - 1));
}
Can this be a fix to make intel_iommu_iova_to_phys() work?
Thank you,
Yonghyun
_______________________________________________
iommu mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/iommu