| From 3b81ac2bdcff0f611cad468329cc726600bb23ba Mon Sep 17 00:00:00 2001 |
| From: Diana Craciun <diana.craciun@nxp.com> |
| Date: Fri, 27 Sep 2019 16:40:34 +0300 |
| Subject: [PATCH] vfio/fsl-mc: Allow userspace to MMAP fsl-mc device MMIO |
| regions |
| |
| Allow userspace to mmap device regions for direct access of |
| fsl-mc devices. |
| |
| Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com> |
| Signed-off-by: Diana Craciun <diana.craciun@nxp.com> |
| --- |
| drivers/vfio/fsl-mc/vfio_fsl_mc.c | 65 +++++++++++++++++++++++++++++++++++++-- |
| 1 file changed, 63 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c |
| +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c |
| @@ -32,7 +32,10 @@ static int vfio_fsl_mc_regions_init(stru |
| |
| vdev->regions[i].addr = res->start; |
| vdev->regions[i].size = PAGE_ALIGN((resource_size(res))); |
| - vdev->regions[i].flags = 0; |
| + vdev->regions[i].flags = VFIO_REGION_INFO_FLAG_MMAP; |
| + vdev->regions[i].flags |= VFIO_REGION_INFO_FLAG_READ; |
| + if (!(mc_dev->regions[i].flags & IORESOURCE_READONLY)) |
| + vdev->regions[i].flags |= VFIO_REGION_INFO_FLAG_WRITE; |
| } |
| |
| vdev->num_regions = mc_dev->obj_desc.region_count; |
| @@ -163,10 +166,68 @@ static ssize_t vfio_fsl_mc_write(void *d |
| return -EINVAL; |
| } |
| |
| +static int vfio_fsl_mc_mmap_mmio(struct vfio_fsl_mc_region region, |
| + struct vm_area_struct *vma) |
| +{ |
| + u64 size = vma->vm_end - vma->vm_start; |
| + u64 pgoff, base; |
| + |
| + pgoff = vma->vm_pgoff & |
| + ((1U << (VFIO_FSL_MC_OFFSET_SHIFT - PAGE_SHIFT)) - 1); |
| + base = pgoff << PAGE_SHIFT; |
| + |
| + if (region.size < PAGE_SIZE || base + size > region.size) |
| + return -EINVAL; |
| + |
| + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); |
| + |
| + vma->vm_pgoff = (region.addr >> PAGE_SHIFT) + pgoff; |
| + |
| + return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, |
| + size, vma->vm_page_prot); |
| +} |
| + |
| static int vfio_fsl_mc_mmap(void *device_data, struct vm_area_struct *vma) |
| { |
| - return -EINVAL; |
| + struct vfio_fsl_mc_device *vdev = device_data; |
| + struct fsl_mc_device *mc_dev = vdev->mc_dev; |
| + unsigned long size, addr; |
| + int index; |
| + |
| + index = vma->vm_pgoff >> (VFIO_FSL_MC_OFFSET_SHIFT - PAGE_SHIFT); |
| + |
| + if (vma->vm_end < vma->vm_start) |
| + return -EINVAL; |
| + if (vma->vm_start & ~PAGE_MASK) |
| + return -EINVAL; |
| + if (vma->vm_end & ~PAGE_MASK) |
| + return -EINVAL; |
| + if (!(vma->vm_flags & VM_SHARED)) |
| + return -EINVAL; |
| + if (index >= vdev->num_regions) |
| + return -EINVAL; |
| + |
| + if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_MMAP)) |
| + return -EINVAL; |
| + |
| + if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_READ) |
| + && (vma->vm_flags & VM_READ)) |
| + return -EINVAL; |
| + |
| + if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_WRITE) |
| + && (vma->vm_flags & VM_WRITE)) |
| + return -EINVAL; |
| + |
| + addr = vdev->regions[index].addr; |
| + size = vdev->regions[index].size; |
| + |
| + vma->vm_private_data = mc_dev; |
| + |
| + return vfio_fsl_mc_mmap_mmio(vdev->regions[index], vma); |
| + |
| + return -EFAULT; |
| } |
| + |
| static int vfio_fsl_mc_init_device(struct vfio_fsl_mc_device *vdev) |
| { |
| struct fsl_mc_device *mc_dev = vdev->mc_dev; |