Similarly to the root/context pgtables, the IOMMU driver also does phys_to_virt when walking the domain pgtables. To make this work properly the physical memory needs to be mapped in at the correct place in the direct map. Register a memory device to support this. The alternative would be to wrap all of the phys_to_virt functions in something which is pkernfs aware. --- fs/pkernfs/iommu.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/fs/pkernfs/iommu.c b/fs/pkernfs/iommu.c index 5d0b256e7dd8..073b9dd48237 100644 --- a/fs/pkernfs/iommu.c +++ b/fs/pkernfs/iommu.c @@ -9,6 +9,7 @@ void pkernfs_get_region_for_ppts(struct file *ppts, struct pkernfs_region *pkern struct pkernfs_inode *pkernfs_inode; unsigned long *mappings_block_vaddr; unsigned long inode_idx; + int rc; /* * For a pkernfs region block, the "mappings_block" field is still @@ -22,7 +23,20 @@ void pkernfs_get_region_for_ppts(struct file *ppts, struct pkernfs_region *pkern mappings_block_vaddr = (unsigned long *)pkernfs_addr_for_block(NULL, pkernfs_inode->mappings_block); set_bit(0, mappings_block_vaddr); - pkernfs_region->vaddr = mappings_block_vaddr; + + dev_set_name(&pkernfs_region->dev, "vfio-ppt-%s", pkernfs_inode->filename); + rc = device_register(&pkernfs_region->dev); + if (rc) + pr_err("device_register failed: %i\n", rc); + + pkernfs_region->pgmap.range.start = pkernfs_base + + (pkernfs_inode->mappings_block * PMD_SIZE); + pkernfs_region->pgmap.range.end = + pkernfs_region->pgmap.range.start + PMD_SIZE - 1; + pkernfs_region->pgmap.nr_range = 1; + pkernfs_region->pgmap.type = MEMORY_DEVICE_GENERIC; + pkernfs_region->vaddr = + devm_memremap_pages(&pkernfs_region->dev, &pkernfs_region->pgmap); pkernfs_region->paddr = pkernfs_base + (pkernfs_inode->mappings_block * (2 << 20)); } void pkernfs_alloc_iommu_root_pgtables(struct pkernfs_region *pkernfs_region) -- 2.40.1