in vfio_iommu_spapr_tce.c [548:605]
static long tce_iommu_build_v2(struct tce_container *container,
struct iommu_table *tbl,
unsigned long entry, unsigned long tce, unsigned long pages,
enum dma_data_direction direction)
{
long i, ret = 0;
unsigned long hpa;
enum dma_data_direction dirtmp;
for (i = 0; i < pages; ++i) {
struct mm_iommu_table_group_mem_t *mem = NULL;
__be64 *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry + i);
ret = tce_iommu_prereg_ua_to_hpa(container,
tce, tbl->it_page_shift, &hpa, &mem);
if (ret)
break;
if (!tce_page_is_contained(container->mm, hpa,
tbl->it_page_shift)) {
ret = -EPERM;
break;
}
/* Preserve offset within IOMMU page */
hpa |= tce & IOMMU_PAGE_MASK(tbl) & ~PAGE_MASK;
dirtmp = direction;
/* The registered region is being unregistered */
if (mm_iommu_mapped_inc(mem))
break;
ret = iommu_tce_xchg_no_kill(container->mm, tbl, entry + i,
&hpa, &dirtmp);
if (ret) {
/* dirtmp cannot be DMA_NONE here */
tce_iommu_unuse_page_v2(container, tbl, entry + i);
pr_err("iommu_tce: %s failed ioba=%lx, tce=%lx, ret=%ld\n",
__func__, entry << tbl->it_page_shift,
tce, ret);
break;
}
if (dirtmp != DMA_NONE)
tce_iommu_unuse_page_v2(container, tbl, entry + i);
*pua = cpu_to_be64(tce);
tce += IOMMU_PAGE_SIZE(tbl);
}
if (ret)
tce_iommu_clear(container, tbl, entry, i);
else
iommu_tce_kill(tbl, entry, pages);
return ret;
}