in io-pgtable-arm-v7s.c [907:1013]
static int __init arm_v7s_do_selftests(void)
{
struct io_pgtable_ops *ops;
struct io_pgtable_cfg cfg = {
.tlb = &dummy_tlb_ops,
.oas = 32,
.ias = 32,
.coherent_walk = true,
.quirks = IO_PGTABLE_QUIRK_ARM_NS,
.pgsize_bitmap = SZ_4K | SZ_64K | SZ_1M | SZ_16M,
};
unsigned int iova, size, iova_start;
unsigned int i, loopnr = 0;
selftest_running = true;
cfg_cookie = &cfg;
ops = alloc_io_pgtable_ops(ARM_V7S, &cfg, &cfg);
if (!ops) {
pr_err("selftest: failed to allocate io pgtable ops\n");
return -EINVAL;
}
/*
* Initial sanity checks.
* Empty page tables shouldn't provide any translations.
*/
if (ops->iova_to_phys(ops, 42))
return __FAIL(ops);
if (ops->iova_to_phys(ops, SZ_1G + 42))
return __FAIL(ops);
if (ops->iova_to_phys(ops, SZ_2G + 42))
return __FAIL(ops);
/*
* Distinct mappings of different granule sizes.
*/
iova = 0;
for_each_set_bit(i, &cfg.pgsize_bitmap, BITS_PER_LONG) {
size = 1UL << i;
if (ops->map(ops, iova, iova, size, IOMMU_READ |
IOMMU_WRITE |
IOMMU_NOEXEC |
IOMMU_CACHE, GFP_KERNEL))
return __FAIL(ops);
/* Overlapping mappings */
if (!ops->map(ops, iova, iova + size, size,
IOMMU_READ | IOMMU_NOEXEC, GFP_KERNEL))
return __FAIL(ops);
if (ops->iova_to_phys(ops, iova + 42) != (iova + 42))
return __FAIL(ops);
iova += SZ_16M;
loopnr++;
}
/* Partial unmap */
i = 1;
size = 1UL << __ffs(cfg.pgsize_bitmap);
while (i < loopnr) {
iova_start = i * SZ_16M;
if (ops->unmap(ops, iova_start + size, size, NULL) != size)
return __FAIL(ops);
/* Remap of partial unmap */
if (ops->map(ops, iova_start + size, size, size, IOMMU_READ, GFP_KERNEL))
return __FAIL(ops);
if (ops->iova_to_phys(ops, iova_start + size + 42)
!= (size + 42))
return __FAIL(ops);
i++;
}
/* Full unmap */
iova = 0;
for_each_set_bit(i, &cfg.pgsize_bitmap, BITS_PER_LONG) {
size = 1UL << i;
if (ops->unmap(ops, iova, size, NULL) != size)
return __FAIL(ops);
if (ops->iova_to_phys(ops, iova + 42))
return __FAIL(ops);
/* Remap full block */
if (ops->map(ops, iova, iova, size, IOMMU_WRITE, GFP_KERNEL))
return __FAIL(ops);
if (ops->iova_to_phys(ops, iova + 42) != (iova + 42))
return __FAIL(ops);
iova += SZ_16M;
}
free_io_pgtable_ops(ops);
selftest_running = false;
pr_info("self test ok\n");
return 0;
}