b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | From 3b81ac2bdcff0f611cad468329cc726600bb23ba Mon Sep 17 00:00:00 2001 |
| 2 | From: Diana Craciun <diana.craciun@nxp.com> |
| 3 | Date: Fri, 27 Sep 2019 16:40:34 +0300 |
| 4 | Subject: [PATCH] vfio/fsl-mc: Allow userspace to MMAP fsl-mc device MMIO |
| 5 | regions |
| 6 | |
| 7 | Allow userspace to mmap device regions for direct access of |
| 8 | fsl-mc devices. |
| 9 | |
| 10 | Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com> |
| 11 | Signed-off-by: Diana Craciun <diana.craciun@nxp.com> |
| 12 | --- |
| 13 | drivers/vfio/fsl-mc/vfio_fsl_mc.c | 65 +++++++++++++++++++++++++++++++++++++-- |
| 14 | 1 file changed, 63 insertions(+), 2 deletions(-) |
| 15 | |
| 16 | --- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c |
| 17 | +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c |
| 18 | @@ -32,7 +32,10 @@ static int vfio_fsl_mc_regions_init(stru |
| 19 | |
| 20 | vdev->regions[i].addr = res->start; |
| 21 | vdev->regions[i].size = PAGE_ALIGN((resource_size(res))); |
| 22 | - vdev->regions[i].flags = 0; |
| 23 | + vdev->regions[i].flags = VFIO_REGION_INFO_FLAG_MMAP; |
| 24 | + vdev->regions[i].flags |= VFIO_REGION_INFO_FLAG_READ; |
| 25 | + if (!(mc_dev->regions[i].flags & IORESOURCE_READONLY)) |
| 26 | + vdev->regions[i].flags |= VFIO_REGION_INFO_FLAG_WRITE; |
| 27 | } |
| 28 | |
| 29 | vdev->num_regions = mc_dev->obj_desc.region_count; |
| 30 | @@ -163,10 +166,68 @@ static ssize_t vfio_fsl_mc_write(void *d |
| 31 | return -EINVAL; |
| 32 | } |
| 33 | |
| 34 | +static int vfio_fsl_mc_mmap_mmio(struct vfio_fsl_mc_region region, |
| 35 | + struct vm_area_struct *vma) |
| 36 | +{ |
| 37 | + u64 size = vma->vm_end - vma->vm_start; |
| 38 | + u64 pgoff, base; |
| 39 | + |
| 40 | + pgoff = vma->vm_pgoff & |
| 41 | + ((1U << (VFIO_FSL_MC_OFFSET_SHIFT - PAGE_SHIFT)) - 1); |
| 42 | + base = pgoff << PAGE_SHIFT; |
| 43 | + |
| 44 | + if (region.size < PAGE_SIZE || base + size > region.size) |
| 45 | + return -EINVAL; |
| 46 | + |
| 47 | + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); |
| 48 | + |
| 49 | + vma->vm_pgoff = (region.addr >> PAGE_SHIFT) + pgoff; |
| 50 | + |
| 51 | + return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, |
| 52 | + size, vma->vm_page_prot); |
| 53 | +} |
| 54 | + |
| 55 | static int vfio_fsl_mc_mmap(void *device_data, struct vm_area_struct *vma) |
| 56 | { |
| 57 | - return -EINVAL; |
| 58 | + struct vfio_fsl_mc_device *vdev = device_data; |
| 59 | + struct fsl_mc_device *mc_dev = vdev->mc_dev; |
| 60 | + unsigned long size, addr; |
| 61 | + int index; |
| 62 | + |
| 63 | + index = vma->vm_pgoff >> (VFIO_FSL_MC_OFFSET_SHIFT - PAGE_SHIFT); |
| 64 | + |
| 65 | + if (vma->vm_end < vma->vm_start) |
| 66 | + return -EINVAL; |
| 67 | + if (vma->vm_start & ~PAGE_MASK) |
| 68 | + return -EINVAL; |
| 69 | + if (vma->vm_end & ~PAGE_MASK) |
| 70 | + return -EINVAL; |
| 71 | + if (!(vma->vm_flags & VM_SHARED)) |
| 72 | + return -EINVAL; |
| 73 | + if (index >= vdev->num_regions) |
| 74 | + return -EINVAL; |
| 75 | + |
| 76 | + if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_MMAP)) |
| 77 | + return -EINVAL; |
| 78 | + |
| 79 | + if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_READ) |
| 80 | + && (vma->vm_flags & VM_READ)) |
| 81 | + return -EINVAL; |
| 82 | + |
| 83 | + if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_WRITE) |
| 84 | + && (vma->vm_flags & VM_WRITE)) |
| 85 | + return -EINVAL; |
| 86 | + |
| 87 | + addr = vdev->regions[index].addr; |
| 88 | + size = vdev->regions[index].size; |
| 89 | + |
| 90 | + vma->vm_private_data = mc_dev; |
| 91 | + |
| 92 | + return vfio_fsl_mc_mmap_mmio(vdev->regions[index], vma); |
| 93 | + |
| 94 | + return -EFAULT; |
| 95 | } |
| 96 | + |
| 97 | static int vfio_fsl_mc_init_device(struct vfio_fsl_mc_device *vdev) |
| 98 | { |
| 99 | struct fsl_mc_device *mc_dev = vdev->mc_dev; |